mirror of
https://github.com/kastenhq/kubestr.git
synced 2024-12-14 11:57:56 +00:00
Kubestr browse PVC functionality (#83)
* browse changes * after onkars review
This commit is contained in:
parent
4d3cb00b76
commit
032878da5f
22 changed files with 2192 additions and 471 deletions
|
@ -77,6 +77,22 @@ var (
|
|||
return CSICheck(ctx, output, outfile, namespace, storageClass, csiCheckVolumeSnapshotClass, csiCheckRunAsUser, containerImage, csiCheckCleanup, csiCheckSkipCFSCheck)
|
||||
},
|
||||
}
|
||||
|
||||
pvcBrowseLocalPort int
|
||||
pvcBrowseCmd = &cobra.Command{
|
||||
Use: "browse [PVC name]",
|
||||
Short: "Browse the contents of a CSI PVC via file browser",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Long: "Browse the contents of a CSI provisioned PVC by cloning the volume and mounting it with a file browser.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return CsiPvcBrowse(context.Background(), args[0],
|
||||
namespace,
|
||||
csiCheckVolumeSnapshotClass,
|
||||
csiCheckRunAsUser,
|
||||
pvcBrowseLocalPort,
|
||||
)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -102,6 +118,13 @@ func init() {
|
|||
csiCheckCmd.Flags().BoolVarP(&csiCheckCleanup, "cleanup", "c", true, "Clean up the objects created by tool")
|
||||
csiCheckCmd.Flags().Int64VarP(&csiCheckRunAsUser, "runAsUser", "u", 0, "Runs the CSI check using pods as a user (int)")
|
||||
csiCheckCmd.Flags().BoolVarP(&csiCheckSkipCFSCheck, "skipCFScheck", "k", false, "Use this flag to skip validating the ability to clone a snapshot.")
|
||||
|
||||
rootCmd.AddCommand(pvcBrowseCmd)
|
||||
pvcBrowseCmd.Flags().StringVarP(&csiCheckVolumeSnapshotClass, "volumesnapshotclass", "v", "", "The name of a VolumeSnapshotClass. (Required)")
|
||||
_ = pvcBrowseCmd.MarkFlagRequired("volumesnapshotclass")
|
||||
pvcBrowseCmd.Flags().StringVarP(&namespace, "namespace", "n", fio.DefaultNS, "The namespace of the PersistentVolumeClaim.")
|
||||
pvcBrowseCmd.Flags().Int64VarP(&csiCheckRunAsUser, "runAsUser", "u", 0, "Runs the inspector pod as a user (int)")
|
||||
pvcBrowseCmd.Flags().IntVarP(&pvcBrowseLocalPort, "localport", "l", 8080, "The local port to expose the inspector")
|
||||
}
|
||||
|
||||
// Execute executes the main command
|
||||
|
@ -209,12 +232,12 @@ func CSICheck(ctx context.Context, output, outfile,
|
|||
testName := "CSI checker test"
|
||||
kubecli, err := kubestr.LoadKubeCli()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to load kubeCLi (%s)", err.Error())
|
||||
fmt.Printf("Failed to load kubeCli (%s)", err.Error())
|
||||
return err
|
||||
}
|
||||
dyncli, err := kubestr.LoadDynCli()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to load kubeCLi (%s)", err.Error())
|
||||
fmt.Printf("Failed to load dynCli (%s)", err.Error())
|
||||
return err
|
||||
}
|
||||
csiCheckRunner := &csi.SnapshotRestoreRunner{
|
||||
|
@ -243,3 +266,37 @@ func CSICheck(ctx context.Context, output, outfile,
|
|||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func CsiPvcBrowse(ctx context.Context,
|
||||
pvcName string,
|
||||
namespace string,
|
||||
volumeSnapshotClass string,
|
||||
runAsUser int64,
|
||||
localPort int,
|
||||
) error {
|
||||
kubecli, err := kubestr.LoadKubeCli()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to load kubeCli (%s)", err.Error())
|
||||
return err
|
||||
}
|
||||
dyncli, err := kubestr.LoadDynCli()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to load dynCli (%s)", err.Error())
|
||||
return err
|
||||
}
|
||||
browseRunner := &csi.PVCBrowseRunner{
|
||||
KubeCli: kubecli,
|
||||
DynCli: dyncli,
|
||||
}
|
||||
err = browseRunner.RunPVCBrowse(ctx, &csitypes.PVCBrowseArgs{
|
||||
PVCName: pvcName,
|
||||
Namespace: namespace,
|
||||
VolumeSnapshotClass: volumeSnapshotClass,
|
||||
RunAsUser: runAsUser,
|
||||
LocalPort: localPort,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to run PVC browser (%s)\n", err.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -22,10 +22,10 @@ Name | CSI Driver Name | Compatible with CSI Version(s) | Description | Persiste
|
|||
[Bigtera VirtualStor (block)](https://github.com/bigtera-ce/ceph-csi) | `csi.block.bigtera.com` | v0.3, v1.0.0, v1.1.0 | A Container Storage Interface (CSI) Driver for Bigtera VirtualStor block storage | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion
|
||||
[Bigtera VirtualStor (filesystem)](https://github.com/bigtera-ce/ceph-csi) | `csi.fs.bigtera.com` | v0.3, v1.0.0, v1.1.0 | A Container Storage Interface (CSI) Driver for Bigtera VirtualStor filesystem | Persistent | Read/Write Multiple Pods | Yes | Expansion
|
||||
[BizFlyCloud Block Storage](https://github.com/bizflycloud/csi-bizflycloud) | `volume.csi.bizflycloud.vn` | v1.2 | A Container Storage Interface (CSI) Driver for BizFly Cloud block storage | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion
|
||||
[CephFS](https://github.com/ceph/ceph-csi) | `cephfs.csi.ceph.com` | v0.3, v1.0.0, v1.1.0, v1.2.0 | A Container Storage Interface (CSI) Driver for CephFS | Persistent | Read/Write Multiple Pods | Yes | Expansion, Snapshot, Clone
|
||||
[Ceph RBD](https://github.com/ceph/ceph-csi) | `rbd.csi.ceph.com` | v0.3, v1.0.0, v1.1.0, v1.2.0 | A Container Storage Interface (CSI) Driver for Ceph RBD | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Topology, Cloning
|
||||
[CephFS](https://github.com/ceph/ceph-csi) | `cephfs.csi.ceph.com` | v0.3, >=v1.0.0 | A Container Storage Interface (CSI) Driver for CephFS | Persistent | Read/Write Multiple Pods | Yes | Expansion, Snapshot, Cloning
|
||||
[Ceph RBD](https://github.com/ceph/ceph-csi) | `rbd.csi.ceph.com` | v0.3, >=v1.0.0 | A Container Storage Interface (CSI) Driver for Ceph RBD | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Topology, Cloning
|
||||
[ChubaoFS](https://github.com/chubaofs/chubaofs-csi) | `csi.chubaofs.com` | v1.0.0 | A Container Storage Interface (CSI) Driver for ChubaoFS Storage | Persistent | Read/Write Multiple Pods | Yes |
|
||||
[Cinder](https://github.com/kubernetes/cloud-provider-openstack/tree/master/pkg/csi/cinder) | `cinder.csi.openstack.org` | v0.3, v1.0, v1.1 | A Container Storage Interface (CSI) Driver for OpenStack Cinder | Persistent and Ephemeral | Depends on the storage backend used | Yes, if storage backend supports it | Raw Block, Snapshot, Expansion
|
||||
[Cinder](https://github.com/kubernetes/cloud-provider-openstack/tree/master/pkg/csi/cinder) | `cinder.csi.openstack.org` | v0.3, v1.0, v1.1.0, v1.2.0, v1.3.0 | A Container Storage Interface (CSI) Driver for OpenStack Cinder | Persistent and Ephemeral | Depends on the storage backend used | Yes, if storage backend supports it | Raw Block, Snapshot, Expansion, Cloning, Topology
|
||||
[cloudscale.ch](https://github.com/cloudscale-ch/csi-cloudscale) | `csi.cloudscale.ch` | v1.0 | A Container Storage Interface (CSI) Driver for the [cloudscale.ch](https://www.cloudscale.ch/) IaaS platform | Persistent | Read/Write Single Pod | Yes |Snapshot
|
||||
[Datatom-InfinityCSI](https://github.com/datatom-infinity/infinity-csi) | `csi-infiblock-plugin` | v0.3, v1.0.0, v1.1.0 | A Container Storage Interface (CSI) Driver for DATATOM Infinity storage | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Topology
|
||||
[Datatom-InfinityCSI (filesystem)](https://github.com/datatom-infinity/infinity-csi) | `csi-infifs-plugin` | v0.3, v1.0.0, v1.1.0 | A Container Storage Interface (CSI) Driver for DATATOM Infinity filesystem storage | Persistent | Read/Write Multiple Pods | Yes | Expansion
|
||||
|
@ -36,11 +36,10 @@ Name | CSI Driver Name | Compatible with CSI Version(s) | Description | Persiste
|
|||
[Dell EMC PowerStore](https://github.com/dell/csi-powerstore) | `csi-powerstore.dellemc.com` | v1.1 | A Container Storage Interface (CSI) Driver for [Dell EMC PowerStore](https://www.delltechnologies.com/en-us/storage/powerstore-storage-appliance.htm) | Persistent and Ephemeral | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Cloning, Topology
|
||||
[Dell EMC Unity](https://github.com/dell/csi-unity) | `csi-unity.dellemc.com` | v1.1 | A Container Storage Interface (CSI) Driver for [Dell EMC Unity](https://www.delltechnologies.com/en-us/storage/unity.htm) | Persistent and Ephemeral | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Cloning, Topology
|
||||
[Dell EMC VxFlexOS](https://github.com/dell/csi-vxflexos) | `csi-vxflexos.dellemc.com` | v1.1 | A Container Storage Interface (CSI) Driver for [Dell EMC VxFlexOS](https://www.delltechnologies.com/en-us/hyperconverged-infrastructure/vxflex.htm) | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Cloning, Topology
|
||||
[democratic-csi](https://github.com/democratic-csi/democratic-csi) | `org.democratic-csi.[X]` | v1.0,v1.1,v1.2 | Generic CSI plugin supporting zfs based solutions ([FreeNAS](https://www.freenas.org/) / [TrueNAS](https://www.truenas.com/) and [ZoL](https://zfsonlinux.org/) solutions such as [Ubuntu](https://ubuntu.com/)) | Persistent and Ephemeral | Read/Write Single Pod (Block Volume) <br/><br/> Read/Write Multiple Pods (File Volume) | Yes | Raw Block, Snapshot, Expansion, Cloning
|
||||
[democratic-csi](https://github.com/democratic-csi/democratic-csi) | `org.democratic-csi.[X]` | v1.0,v1.1,v1.2,v1.3,v1.4,v1.5 | Generic CSI plugin supporting zfs based solutions ([FreeNAS](https://www.freenas.org/) / [TrueNAS](https://www.truenas.com/) and [ZoL](https://zfsonlinux.org/) solutions such as [Ubuntu](https://ubuntu.com/)), [Synology](https://www.synology.com/), and more | Persistent and Ephemeral | Read/Write Single Pod (Block Volume) <br/><br/> Read/Write Multiple Pods (File Volume) | Yes | Raw Block, Snapshot, Expansion, Cloning
|
||||
[Diamanti-CSI](https://diamanti.com/use-cases/io-acceleration/#csi) | `dcx.csi.diamanti.com` | v1.0 | A Container Storage Interface (CSI) Driver for Diamanti DCX Platform | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion
|
||||
[DigitalOcean Block Storage](https://github.com/digitalocean/csi-digitalocean) | `dobs.csi.digitalocean.com` | v0.3, v1.0 | A Container Storage Interface (CSI) Driver for DigitalOcean Block Storage | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion
|
||||
[Dothill-CSI](https://github.com/enix/dothill-csi) | `dothill.csi.enix.io` | v1.3 | Generic CSI plugin supporting [Seagate AssuredSan](https://www.seagate.com/fr/fr/support/dothill-san/assuredsan-pro-5000-series/) appliances such as [HPE MSA](https://www.hpe.com/us/en/storage/flash-hybrid.html), [Dell EMC PowerVault ME4](https://www.dell.com/fr-fr/work/shop/productdetailstxn/powervault-me4-series) and others ... | Persistent | Read/Write Single Node | Yes | Snapshot, Expansion
|
||||
[DriveScale](https://github.com/DriveScale/k8s-plugins) | `csi.drivescale.com` | v1.0 |A Container Storage Interface (CSI) Driver for DriveScale software composable infrastructure solution | Persistent | Read/Write Single Pod | Yes |
|
||||
[Ember CSI](https://ember-csi.io) | `[x].ember-csi.io` | v0.2, v0.3, v1.0 | Multi-vendor CSI plugin supporting over 80 Drivers to provide block and mount storage to Container Orchestration systems. | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot
|
||||
[Excelero NVMesh](https://github.com/Excelero/nvmesh-csi-driver) | `nvmesh-csi.excelero.com` | v1.0, v1.1 | A Container Storage Interface (CSI) Driver for Excelero NVMesh | Persistent | Read/Write Multiple Pods | Yes | Raw Block, Expansion
|
||||
[GCE Persistent Disk](https://github.com/kubernetes-sigs/gcp-compute-persistent-disk-csi-driver) | `pd.csi.storage.gke.io` | v0.3, v1.0 | A Container Storage Interface (CSI) Driver for Google Compute Engine Persistent Disk (GCE PD) | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Topology
|
||||
|
@ -52,10 +51,11 @@ Name | CSI Driver Name | Compatible with CSI Version(s) | Description | Persiste
|
|||
[Hedvig](https://documentation.commvault.com/commvault/hedvig/others/pdf/Hedvig_CSI_User_Guide.pdf) | `io.hedvig.csi` | v1.0 | A Container Storage Interface (CSI) Driver for Hedvig | Persistent | Read/Write Multiple Pods | Yes | Raw Block, Snapshot, Expansion
|
||||
[Hetzner Cloud Volumes CSI](https://github.com/hetznercloud/csi-driver) | `csi.hetzner.cloud` | v0.3, v1.0 | A Container Storage Interface (CSI) Driver for Hetzner Cloud Volumes | Persistent | Read/Write Single Pod | Yes | Raw Block, Expansion
|
||||
[Hitachi Vantara](https://knowledge.hitachivantara.com/Documents/Adapters_and_Drivers/Storage_Adapters_and_Drivers/Containers) | `hspc.csi.hitachi.com` | v1.2 | A Container Storage Interface (CSI) Driver for VSP series Storage | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Cloning
|
||||
[HPE](https://github.com/hpe-storage/csi-driver) | `csi.hpe.com` | v1.0, v1.1, v1.2 | A [multi-platform](https://scod.hpedev.io/csi_driver) Container Storage Interface (CSI) driver. Supports [HPE Nimble Storage](https://hpe.com/storage/nimble), [HPE Primera](https://hpe.com/storage/primera) and [HPE 3PAR](https://hpe.com/storage/3par) | Persistent and Ephemeral | Read/Write Multiple Pods | Yes | Raw Block, Snapshot, Expansion, Cloning
|
||||
[HPE](https://github.com/hpe-storage/csi-driver) | `csi.hpe.com` | v1.3 | A [multi-platform](https://scod.hpedev.io/csi_driver) Container Storage Interface (CSI) driver. Supports [HPE Alletra](https://hpe.com/storage/alletra), [Nimble Storage](https://hpe.com/storage/nimble), [Primera](https://hpe.com/storage/primera) and [3PAR](https://hpe.com/storage/3par) | Persistent and Ephemeral | Read/Write Multiple Pods | Yes | Raw Block, Snapshot, Expansion, Cloning
|
||||
[HPE Ezmeral (MapR)](https://github.com/mapr/mapr-csi) | `com.mapr.csi-kdf` | v1.3 | A Container Storage Interface (CSI) Driver for HPE Ezmeral Data Fabric | Persistent | Read/Write Multiple Pods | Yes | Raw Block, Snapshot, Expansion, Cloning
|
||||
[Huawei Storage CSI](https://github.com/Huawei/eSDK_K8S_Plugin) | `csi.huawei.com` | v1.0, v1.1, v1.2 | A Container Storage Interface (CSI) Driver for FusionStorage, OceanStor 100D, OceanStor Pacific, OceanStor Dorado V3, OceanStor Dorado V6, OceanStor V3, OceanStor V5 | Persistent | Read/Write Multiple Pod | Yes | Snapshot, Expansion, Cloning
|
||||
[HyperV CSI](https://github.com/Zetanova/hyperv-csi-driver) | `eu.zetanova.csi.hyperv` | v1.0, v1.1 | A Container Storage Interface (CSI) driver to manage hyperv hosts | Persistent | Read/Write Multiple Pods | Yes |
|
||||
[IBM Block Storage](https://github.com/ibm/ibm-block-csi-driver) | `block.csi.ibm.com` | v1.0, v1.1, v1.2 | A Container Storage Interface (CSI) [Driver](https://www.ibm.com/support/knowledgecenter/SSRQ8T) for IBM Spectrum Virtualize Family, IBM FlashSystem A9000 and A9000R, IBM DS8880 and DS8900. | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Cloning
|
||||
[IBM Block Storage](https://github.com/ibm/ibm-block-csi-driver) | `block.csi.ibm.com` | v1.0, v1.1, v1.2 | A Container Storage Interface (CSI) [Driver](https://www.ibm.com/docs/en/stg-block-csi-driver) for IBM Spectrum Virtualize Family, IBM FlashSystem A9000 and A9000R, IBM DS8000 Family 8.x and higher. | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Cloning, Topology
|
||||
[IBM Spectrum Scale](https://github.com/IBM/ibm-spectrum-scale-csi) | `spectrumscale.csi.ibm.com` | v1.0, v1.1 | A Container Storage Interface (CSI) [Driver](https://www.ibm.com/docs/en/spectrum-scale-csi) for the IBM Spectrum Scale File System | Persistent | Read/Write Multiple Pod | Yes | Snapshot
|
||||
[IBM Cloud Block Storage VPC CSI Driver](https://cloud.ibm.com/docs/containers?topic=containers-vpc-block) | `vpc.block.csi.ibm.io` | v1.0 | A Container Storage Interface (CSI) [Driver](https://cloud.ibm.com/docs/containers?topic=containers-vpc-block) for IBM Cloud Kubernetes Service and Red Hat OpenShift on IBM Cloud | Persistent | Read/Write Single Pod | Yes | Raw Block |
|
||||
[Infinidat](https://github.com/Infinidat/infinibox-csi-driver) | `infinibox-csi-driver` | v1.0, v1.1 | A Container Storage Interface (CSI) Driver for Infinidat [InfiniBox](https://infinidat.com/en/products-technology/infinibox) | Persistent | Read/Write Multiple Pods | Yes | Raw Block, Snapshot, Expansion, Cloning
|
||||
|
@ -63,25 +63,26 @@ Name | CSI Driver Name | Compatible with CSI Version(s) | Description | Persiste
|
|||
[Intel PMEM-CSI](https://github.com/intel/pmem-csi) | `pmem-csi.intel.com` | v1.0 | A Container Storage Interface (CSI) driver for [PMEM](https://pmem.io/) from Intel | Persistent and Ephemeral | Read/Write Single Pod | Yes | Raw Block
|
||||
[Intelliflash Block Storage](https://github.com/DDNStorage/intelliflash-csi-block-driver) | `intelliflash-csi-block-driver.intelliflash.com` | v1.0, v1.1, v1.2 | A Container Storage Interface (CSI) Driver for Intelliflash Block Storage | Persistent | Read/Write Multiple Pods | Yes | Snapshot, Expansion, Cloning, Topology
|
||||
[Intelliflash File Storage](https://github.com/DDNStorage/intelliflash-csi-file-driver) | `intelliflash-csi-file-driver.intelliflash.com` | v1.0, v1.1, v1.2 | A Container Storage Interface (CSI) Driver for Intelliflash File Storage | Persistent | Read/Write Multiple Pods | Yes | Snapshot, Expansion, Cloning, Topology
|
||||
[ionir ](https://github.com/ionir-cloud) | `ionir` | v1.2 | A Container Storage Interface (CSI) Driver for [ionir](https://www.ionir.com/) Kubernetes-Native Storage | Persistent | Read/Write Single Pod | Yes | Raw Block, Cloning
|
||||
[JuiceFS](https://github.com/juicedata/juicefs-csi-driver) | `csi.juicefs.com` | v0.3, v1.0 | A Container Storage Interface (CSI) Driver for JuiceFS File System | Persistent | Read/Write Multiple Pod | Yes |
|
||||
[kaDalu](https://github.com/kadalu/kadalu) | `org.kadalu.gluster` | v0.3 | A CSI Driver (and operator) for GlusterFS | Persistent | Read/Write Multiple Pods | Yes |
|
||||
[KumoScale Block Storage](https://github.com/KioxiaAmerica/kumoscale-csi) | `kumoscale.kioxia.com` | v1.0 | A Container Storage Interface (CSI) Driver for KumoScale Block Storage | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Topology
|
||||
[Linode Block Storage](https://github.com/linode/linode-blockstorage-csi-driver) | `linodebs.csi.linode.com` | v1.0 | A Container Storage Interface (CSI) Driver for Linode Block Storage | Persistent | Read/Write Single Pod | Yes |
|
||||
[LINSTOR](https://github.com/piraeusdatastore/linstor-csi) | `linstor.csi.linbit.com` | v1.2 | A Container Storage Interface (CSI) Driver for [LINSTOR](https://www.linbit.com/en/linstor/) volumes | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Cloning, Topology
|
||||
[Longhorn](https://github.com/longhorn/longhorn) | `driver.longhorn.io` | v1.1 | A Container Storage Interface (CSI) Driver for [Longhorn](https://longhorn.io/) volumes | Persistent | Read/Write Single Node | Yes | Raw Block
|
||||
[Longhorn](https://github.com/longhorn/longhorn) | `driver.longhorn.io` | v1.2 | A Container Storage Interface (CSI) Driver for [Longhorn](https://longhorn.io/) volumes | Persistent | Read/Write Single Node | Yes | Raw Block
|
||||
[MacroSAN](https://github.com/macrosan-csi/macrosan-csi-driver) | `csi-macrosan` | v1.0 | A Container Storage Interface (CSI) Driver for MacroSAN Block Storage | Persistent | Read/Write Single Pod | Yes |
|
||||
[Manila](https://github.com/kubernetes/cloud-provider-openstack/tree/master/pkg/csi/manila) | `manila.csi.openstack.org` | v1.1, v1.2 | A Container Storage Interface (CSI) Driver for OpenStack Shared File System Service (Manila) | Persistent | Read/Write Multiple Pods | Yes | Snapshot, Topology
|
||||
[MapR](https://github.com/mapr/mapr-csi) | `com.mapr.csi-kdf` | v1.0 | A Container Storage Interface (CSI) Driver for MapR Data Platform | Persistent | Read/Write Multiple Pods | Yes | Snapshot
|
||||
[MooseFS](https://github.com/moosefs/moosefs-csi) | `com.tuxera.csi.moosefs` | v1.0 | A Container Storage Interface (CSI) Driver for [MooseFS](https://moosefs.com/) clusters. | Persistent | Read/Write Multiple Pods | Yes |
|
||||
[NetApp](https://github.com/NetApp/trident) | `csi.trident.netapp.io` | v1.0, v1.1, v1.2 | A Container Storage Interface (CSI) Driver for NetApp's [Trident](https://netapp-trident.readthedocs.io/) container storage orchestrator | Persistent | Read/Write Multiple Pods | Yes | Raw Block, Snapshot, Expansion, Cloning, Topology
|
||||
[NetApp](https://github.com/NetApp/trident) | `csi.trident.netapp.io` | v1.0, v1.1, v1.2, v1.3 | A Container Storage Interface (CSI) Driver for NetApp's [Trident](https://netapp-trident.readthedocs.io/) container storage orchestrator | Persistent | Read/Write Multiple Pods | Yes | Raw Block, Snapshot, Expansion, Cloning, Topology
|
||||
[NexentaStor File Storage](https://github.com/Nexenta/nexentastor-csi-driver) | `nexentastor-csi-driver.nexenta.com` | v1.0, v1.1, v1.2 | A Container Storage Interface (CSI) Driver for NexentaStor File Storage | Persistent | Read/Write Multiple Pods | Yes | Snapshot, Expansion, Cloning, Topology
|
||||
[NexentaStor Block Storage](https://github.com/Nexenta/nexentastor-csi-driver-block) | `nexentastor-block-csi-driver.nexenta.com` | v1.0, v1.1, v1.2 | A Container Storage Interface (CSI) Driver for NexentaStor over iSCSI protocol | Persistent | Read/Write Multiple Pods | Yes | Snapshot, Expansion, Cloning, Topology, Raw block
|
||||
[Nutanix](https://github.com/nutanix/csi-plugin) | `com.nutanix.csi` | v0.3, v1.0, v1.2 | A Container Storage Interface (CSI) Driver for Nutanix | Persistent | "Read/Write Single Pod" with Nutanix Volumes and "Read/Write Multiple Pods" with Nutanix Files | Yes | Raw Block, Snapshot, Expansion, Cloning
|
||||
[OpenEBS](https://github.com/openebs/csi)| `cstor.csi.openebs.io` | v1.0 | A Container Storage Interface (CSI) Driver for [OpenEBS](https://www.openebs.io/)| Persistent | Read/Write Single Pod | Yes | Expansion, Snapshot, Cloning
|
||||
[Open-E](https://github.com/open-e/JovianDSS-KubernetesCSI) | `com.open-e.joviandss.csi` | v1.0 | A Container Storage Interface (CSI) Driver for Open-E JovianDSS Storage | Persistent | Read/Write Single Pod | Yes | Snapshot, Cloning
|
||||
[Open-Local](https://github.com/alibaba/open-local) | `local.csi.alibaba.com` | v1.0 | A Container Storage Interface (CSI) Driver for Local Storage | Persistent | Read/Write Single Pod | Yes | Raw Block, Expansion, Snapshot
|
||||
[Oracle Cloud Infrastructure(OCI) Block Storage](https://github.com/oracle/oci-cloud-controller-manager/blob/master/container-storage-interface.md) | `blockvolume.csi.oraclecloud.com` | v1.1 | A Container Storage Interface (CSI) Driver for Oracle Cloud Infrastructure (OCI) Block Storage | Persistent | Read/Write Single Pod | Yes | Topology
|
||||
[oVirt](https://github.com/openshift/ovirt-csi-driver) | `csi.ovirt.org` | v1.0 | A Container Storage Interface (CSI) Driver for [oVirt](https://ovirt.org) | Persistent | Read/Write Single Pod | Yes | Block, File Storage
|
||||
[Portworx](https://github.com/libopenstorage/openstorage/tree/master/csi) | `pxd.openstorage.org` | v0.3, v1.1 | A Container Storage Interface (CSI) Driver for [Portworx](https://docs.portworx.com/portworx-install-with-kubernetes/storage-operations/csi/) | Persistent | Read/Write Multiple Pods | Yes | Snapshot, Expansion
|
||||
[Portworx](https://github.com/libopenstorage/openstorage/tree/master/csi) | `pxd.portworx.com` | v1.4 | A Container Storage Interface (CSI) Driver for [Portworx](https://docs.portworx.com/portworx-install-with-kubernetes/storage-operations/csi/) | Persistent and Ephemeral | Read/Write Multiple Pods | Yes | Snapshot, Expansion, Raw Block, Cloning
|
||||
[Pure Storage CSI](https://github.com/purestorage/pso-csi)| `pure-csi` | v1.0, v1.1, v1.2, v1.3 | A Container Storage Interface (CSI) Driver for Pure Storage's [Pure Service Orchestrator](https://purestorage.com/containers) | Persistent and Ephemeral | Read/Write Multiple Pods | Yes | Snapshot, Cloning, Raw Block, Topology, Expansion
|
||||
[QingCloud CSI](https://github.com/yunify/qingcloud-csi)| `disk.csi.qingcloud.com` | v1.1 | A Container Storage Interface (CSI) Driver for QingCloud Block Storage | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Cloning
|
||||
[QingStor CSI](https://github.com/yunify/qingstor-csi) | `neonsan.csi.qingstor.com` | v0.3, v1.1 | A Container Storage Interface (CSI) Driver for NeonSAN storage system | Persistent | Read/Write Multiple Pods | Yes | Raw Block, Snapshot, Expansion, Cloning
|
||||
|
@ -91,6 +92,7 @@ Name | CSI Driver Name | Compatible with CSI Version(s) | Description | Persiste
|
|||
[Sangfor-EDS-File-Storage](https://github.com/evan37717/sangfor-eds-csi) | `eds.csi.file.sangfor.com` | v1.0 | A Container Storage Interface (CSI) Driver for Sangfor Distributed File Storage(EDS) | Persistent | Read/Write Multiple Pods | Yes |
|
||||
[Sangfor-EDS-Block-Storage](https://github.com/eds-wzc/sangfor-eds-csi) | `eds.csi.block.sangfor.com` | v1.0 | A Container Storage Interface (CSI) Driver for Sangfor Block Storage(EDS) | Persistent | Read/Write Single Pod | Yes |
|
||||
[Scaleway CSI](https://github.com/scaleway/scaleway-csi) | `csi.scaleway.com` | v1.2.0 | Container Storage Interface (CSI) Driver for [Scaleway Block Storage](https://www.scaleway.com/block-storage/) | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Topology
|
||||
[Seagate Exos X](https://github.com/Seagate/seagate-exos-x-csi) | `csi-exos-x.seagate.com` | v1.3 | CSI driver for [Seagate Exos X](https://www.seagate.com/products/storage/data-storage-systems/raid/) and OEM systems | Persistent | Read/Write Single Pod | Yes | Snapshot, Expansion, Cloning
|
||||
[SeaweedFS](https://github.com/seaweedfs/seaweedfs-csi-driver) | `seaweedfs-csi-driver` | v1.0 | A Container Storage Interface (CSI Driver for [SeaweedFS](https://github.com/chrislusf/seaweedfs)) | Persistent | Read/Write Multiple Pods | Yes |
|
||||
[Secrets Store CSI Driver](https://github.com/kubernetes-sigs/secrets-store-csi-driver) | `secrets-store.csi.k8s.io` | v0.0.10 | A Container Storage Interface (CSI) Driver for mounting secrets, keys, and certs stored in enterprise-grade external secrets stores as volumes. | Ephemeral | N/A | N/A |
|
||||
[SmartX](http://www.smartx.com/?locale=en) | `csi-smtx-plugin` | v1.0 | A Container Storage Interface (CSI) Driver for SmartX ZBS Storage | Persistent | Read/Write Multiple Pods | Yes | Snapshot, Expansion
|
||||
|
@ -99,6 +101,7 @@ Name | CSI Driver Name | Compatible with CSI Version(s) | Description | Persiste
|
|||
[StorageOS](https://docs.storageos.com/docs/platforms/kubernetes/install/) | `storageos` | v0.3, v1.0 | A Container Storage Interface (CSI) Driver for [StorageOS](https://storageos.com/) | Persistent | Read/Write Multiple Pods | Yes |
|
||||
[Storidge](https://docs.storidge.com/kubernetes_storage/overview.html) | `csi.cio.storidge.com` | v0.3, v1.0 | A Container Storage Interface (CSI) Driver for [Storidge CIO](https://storidge.com/) | Persistent | Read/Write Multiple Pods | Yes | Snapshot, Expansion
|
||||
[StorPool](https://kb.storpool.com/storpool_integrations/github/kubernetes.html) | `csi-driver.storpool.com` | v1.0 | A Container Storage Interface (CSI) Driver for [StorPool](https://storpool.com/) | Persistent and Ephemeral | Read/Write Multiple Pods | Yes | Expansion
|
||||
[Synology](https://github.com/SynologyOpenSource/synology-csi) | `csi.san.synology.com` | v1.0 | A Container Storage Interface (CSI) Driver for Synology NAS | Persistent | Read/Write Multiple Pods | Yes | Snapshot, Expansion, Cloning
|
||||
[Tencent Cloud Block Storage](https://github.com/TencentCloud/kubernetes-csi-tencentcloud)| `com.tencent.cloud.csi.cbs` | v1.0 | A Container Storage Interface (CSI) Driver for Tencent Cloud Block Storage | Persistent | Read/Write Single Pod | Yes | Snapshot
|
||||
[Tencent Cloud File Storage](https://github.com/TencentCloud/kubernetes-csi-tencentcloud)| `com.tencent.cloud.csi.cfs` | v1.0 | A Container Storage Interface (CSI) Driver for Tencent Cloud File Storage | Persistent | Read/Write Multiple Pods | Yes |
|
||||
[Tencent Cloud Object Storage](https://github.com/TencentCloud/kubernetes-csi-tencentcloud)| `com.tencent.cloud.csi.cosfs` | v1.0 | A Container Storage Interface (CSI) Driver for Tencent Cloud Object Storage | Persistent | Read/Write Multiple Pods | No |
|
||||
|
@ -107,6 +110,7 @@ Name | CSI Driver Name | Compatible with CSI Version(s) | Description | Persiste
|
|||
[XSKY-EBS](https://xsky-storage.github.io/xsky-csi-driver/csi-block.html) | `csi.block.xsky.com` | v1.0 | A Container Storage Interface (CSI) Driver for XSKY Distributed Block Storage (X-EBS) | Persistent | Read/Write Single Pod | Yes | Raw Block, Snapshot, Expansion, Cloning
|
||||
[XSKY-EUS](https://xsky-storage.github.io/xsky-csi-driver/csi-fs.html) | `csi.fs.xsky.com` | v1.0 | A Container Storage Interface (CSI) Driver for XSKY Distributed File Storage (X-EUS) | Persistent | Read/Write Multiple Pods | Yes |
|
||||
[Vault](https://github.com/kubevault/csi-driver) | `secrets.csi.kubevault.com` | v1.0 | A Container Storage Interface (CSI) Driver for mounting HashiCorp Vault secrets as volumes. | Ephemeral | N/A | N/A |
|
||||
[VDA](https://virtual-disk-array.readthedocs.io/en/latest/Introduction.html) | `csi.vda.io` | v1.0 | An open source block storage system base on SPDK | Persistent | Read/Write Single Pod | N/A |
|
||||
[Veritas InfoScale Volumes](https://www.veritas.com/solution/virtualization/containers.html) | `org.veritas.infoscale` | v1.2 | A Container Storage Interface (CSI) Driver for Veritas InfoScale volumes | Persistent | Read/Write Multiple Pods | Yes | Snapshot, Expansion, Cloning
|
||||
[vSphere](https://github.com/kubernetes-sigs/vsphere-csi-driver) | `csi.vsphere.vmware.com` | v1.0 | A Container Storage Interface (CSI) Driver for VMware vSphere | Persistent | Read/Write Single Pod (Block Volume) <br/><br/> Read/Write Multiple Pods (File Volume) | Yes | Raw Block,<br/><br/>Expansion (Block Volume),<br/><br/>Topology Aware (Block Volume)
|
||||
[Vultr Block Storage](https://github.com/vultr/vultr-csi) | `block.csi.vultr.com` | v1.2 | A Container Storage Interface (CSI) Driver for Vultr Block Storage | Persistent | Read/Write Single Pod | Yes |
|
||||
|
|
8
go.mod
8
go.mod
|
@ -11,12 +11,10 @@ require (
|
|||
github.com/jarcoal/httpmock v1.0.5 // indirect
|
||||
github.com/kanisterio/kanister v0.0.0-20210805190523-86f566052e0e
|
||||
github.com/kubernetes-csi/external-snapshotter/client/v4 v4.0.0
|
||||
github.com/onsi/ginkgo v1.12.0 // indirect
|
||||
github.com/onsi/gomega v1.9.0 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/spf13/cobra v1.1.1
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
|
||||
k8s.io/api v0.20.1
|
||||
k8s.io/apimachinery v0.20.1
|
||||
k8s.io/client-go v0.20.1
|
||||
k8s.io/api v0.22.2
|
||||
k8s.io/apimachinery v0.22.2
|
||||
k8s.io/client-go v0.22.2
|
||||
)
|
||||
|
|
39
go.sum
39
go.sum
|
@ -287,6 +287,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
|||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
|
||||
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs=
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
|
@ -397,6 +399,8 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
|
|||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
|
@ -448,6 +452,7 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
|
|||
github.com/gomodule/redigo v1.8.3/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
github.com/google/fswalker v0.2.1-0.20200214223026-f0e929ba4126/go.mod h1:ZSEBqY0IHKqWPeAbTyvccv9bb9vCnaQfHe31cm911Ng=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
|
@ -512,8 +517,11 @@ github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsC
|
|||
github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I=
|
||||
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
|
||||
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
|
||||
github.com/googleapis/gnostic v0.5.3 h1:2qsuRm+bzgwSIKikigPASa2GhW8H2Dn4Qq7UxD8K/48=
|
||||
github.com/googleapis/gnostic v0.5.3/go.mod h1:TRWw1s4gxBGjSe301Dai3c7wXJAZy57+/6tawkOvqHQ=
|
||||
github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
|
||||
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
|
||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
|
@ -640,6 +648,7 @@ github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dv
|
|||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
|
@ -750,6 +759,8 @@ github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxd
|
|||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mmcloughlin/avo v0.0.0-20201105074841-5d2f697d268f/go.mod h1:6aKT4zZIrpGqB3RpFU14ByCSSyKY6LfJz4J/JJChHfI=
|
||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
|
@ -785,6 +796,7 @@ github.com/ncw/directio v1.0.5/go.mod h1:rX/pKEYkOXBGOggmcyJeJGloCkleSvphPx2eV3t
|
|||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nsqio/go-nsq v1.0.8/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
|
@ -797,6 +809,8 @@ github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
|
|||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
|
||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
|
@ -804,6 +818,7 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
|
|||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
|
||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/openshift/api v0.0.0-20200521101457-60c476765272/go.mod h1:TkhafijfTiRi1Q3120/ZSE4oIWKQ4DGRh3byPywv4Mw=
|
||||
github.com/openshift/api v0.0.0-20200526144822-34f54f12813a h1:riE/kCXnb051RWT/z+DytxKEZ3+JromVDl79rXAKyFY=
|
||||
|
@ -1097,6 +1112,7 @@ golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWP
|
|||
golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
|
@ -1181,6 +1197,7 @@ golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/
|
|||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||
|
@ -1202,6 +1219,7 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
|||
golang.org/x/net v0.0.0-20210420210106-798c2154c571/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210505214959-0714010a04ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
|
@ -1265,6 +1283,7 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -1291,6 +1310,7 @@ golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8=
|
||||
|
@ -1338,6 +1358,7 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
@ -1364,6 +1385,8 @@ golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxb
|
|||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -1425,6 +1448,7 @@ golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roY
|
|||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d h1:szSOL78iTCl0LF1AMjhSWJj8tIM0KixlUUnBtYXsmd8=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
|
@ -1435,6 +1459,7 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f
|
|||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
|
@ -1677,6 +1702,8 @@ k8s.io/api v0.19.0 h1:XyrFIJqTYZJ2DU7FBE/bSPz7b1HvbVBuBf07oeo6eTc=
|
|||
k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw=
|
||||
k8s.io/api v0.20.1 h1:ud1c3W3YNzGd6ABJlbFfKXBKXO+1KdGfcgGGNgFR03E=
|
||||
k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo=
|
||||
k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw=
|
||||
k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8=
|
||||
k8s.io/apiextensions-apiserver v0.20.1 h1:ZrXQeslal+6zKM/HjDXLzThlz/vPSxrfK3OqL8txgVQ=
|
||||
k8s.io/apiextensions-apiserver v0.20.1/go.mod h1:ntnrZV+6a3dB504qwC5PN/Yg9PBiDNt1EVqbW2kORVk=
|
||||
k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko=
|
||||
|
@ -1684,12 +1711,16 @@ k8s.io/apimachinery v0.19.0 h1:gjKnAda/HZp5k4xQYjL0K/Yb66IvNqjthCb03QlKpaQ=
|
|||
k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
|
||||
k8s.io/apimachinery v0.20.1 h1:LAhz8pKbgR8tUwn7boK+b2HZdt7MiTu2mkYtFMUjTRQ=
|
||||
k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
|
||||
k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk=
|
||||
k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
|
||||
k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
|
||||
k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw=
|
||||
k8s.io/client-go v0.19.0 h1:1+0E0zfWFIWeyRhQYWzimJOyAk2UT7TiARaLNwJCf7k=
|
||||
k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU=
|
||||
k8s.io/client-go v0.20.1 h1:Qquik0xNFbK9aUG92pxHYsyfea5/RPO9o9bSywNor+M=
|
||||
k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
|
||||
k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc=
|
||||
k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U=
|
||||
k8s.io/code-generator v0.18.3/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c=
|
||||
k8s.io/code-generator v0.19.0/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk=
|
||||
k8s.io/code-generator v0.20.1/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg=
|
||||
|
@ -1708,17 +1739,23 @@ k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A=
|
|||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ=
|
||||
k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM=
|
||||
k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
|
||||
k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
|
||||
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 h1:+WnxoVtG8TMiudHBSEtrVL1egv36TkkJm+bA8AxicmQ=
|
||||
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
|
||||
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd h1:sOHNzJIkytDF6qadMNKhhDRpc6ODik8lVC6nOur7B2c=
|
||||
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU=
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/utils v0.0.0-20200729134348-d5654de09c73 h1:uJmqzgNWG7XyClnU/mLPBWwfKKF1K8Hf8whTseBgJcg=
|
||||
k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw=
|
||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g=
|
||||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
|
@ -1732,6 +1769,8 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSq
|
|||
sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
|
|
392
pkg/csi/csi_ops.go
Normal file
392
pkg/csi/csi_ops.go
Normal file
|
@ -0,0 +1,392 @@
|
|||
package csi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/kanisterio/kanister/pkg/kube"
|
||||
kankube "github.com/kanisterio/kanister/pkg/kube"
|
||||
kansnapshot "github.com/kanisterio/kanister/pkg/kube/snapshot"
|
||||
"github.com/kastenhq/kubestr/pkg/common"
|
||||
"github.com/kastenhq/kubestr/pkg/csi/types"
|
||||
snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
"github.com/pkg/errors"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
sv1 "k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
pf "k8s.io/client-go/tools/portforward"
|
||||
"k8s.io/client-go/transport/spdy"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_argument_validator.go -package=mocks . ArgumentValidator
|
||||
type ArgumentValidator interface {
|
||||
//Rename
|
||||
ValidatePVC(ctx context.Context, pvcName, namespace string) (*v1.PersistentVolumeClaim, error)
|
||||
FetchPV(ctx context.Context, pvName string) (*v1.PersistentVolume, error)
|
||||
ValidateNamespace(ctx context.Context, namespace string) error
|
||||
ValidateStorageClass(ctx context.Context, storageClass string) (*sv1.StorageClass, error)
|
||||
ValidateVolumeSnapshotClass(ctx context.Context, volumeSnapshotClass string, groupVersion *metav1.GroupVersionForDiscovery) (*unstructured.Unstructured, error)
|
||||
}
|
||||
|
||||
type validateOperations struct {
|
||||
kubeCli kubernetes.Interface
|
||||
dynCli dynamic.Interface
|
||||
}
|
||||
|
||||
func (o *validateOperations) ValidatePVC(ctx context.Context, pvcName, namespace string) (*v1.PersistentVolumeClaim, error) {
|
||||
if o.kubeCli == nil {
|
||||
return nil, fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
return o.kubeCli.CoreV1().PersistentVolumeClaims(namespace).Get(ctx, pvcName, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func (o *validateOperations) FetchPV(ctx context.Context, pvName string) (*v1.PersistentVolume, error) {
|
||||
if o.kubeCli == nil {
|
||||
return nil, fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
return o.kubeCli.CoreV1().PersistentVolumes().Get(ctx, pvName, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func (o *validateOperations) ValidateNamespace(ctx context.Context, namespace string) error {
|
||||
if o.kubeCli == nil {
|
||||
return fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
_, err := o.kubeCli.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *validateOperations) ValidateStorageClass(ctx context.Context, storageClass string) (*sv1.StorageClass, error) {
|
||||
if o.kubeCli == nil {
|
||||
return nil, fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
return o.kubeCli.StorageV1().StorageClasses().Get(ctx, storageClass, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func (o *validateOperations) ValidateVolumeSnapshotClass(ctx context.Context, volumeSnapshotClass string, groupVersion *metav1.GroupVersionForDiscovery) (*unstructured.Unstructured, error) {
|
||||
if o.dynCli == nil {
|
||||
return nil, fmt.Errorf("dynCli not initialized")
|
||||
}
|
||||
VolSnapClassGVR := schema.GroupVersionResource{Group: common.SnapGroupName, Version: groupVersion.Version, Resource: common.VolumeSnapshotClassResourcePlural}
|
||||
return o.dynCli.Resource(VolSnapClassGVR).Get(ctx, volumeSnapshotClass, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_application_creator.go -package=mocks . ApplicationCreator
|
||||
type ApplicationCreator interface {
|
||||
CreatePVC(ctx context.Context, args *types.CreatePVCArgs) (*v1.PersistentVolumeClaim, error)
|
||||
CreatePod(ctx context.Context, args *types.CreatePodArgs) (*v1.Pod, error)
|
||||
WaitForPodReady(ctx context.Context, namespace string, podName string) error
|
||||
}
|
||||
|
||||
type applicationCreate struct {
|
||||
kubeCli kubernetes.Interface
|
||||
}
|
||||
|
||||
func (c *applicationCreate) CreatePVC(ctx context.Context, args *types.CreatePVCArgs) (*v1.PersistentVolumeClaim, error) {
|
||||
if c.kubeCli == nil {
|
||||
return nil, fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
if err := args.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pvc := &v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: args.GenerateName,
|
||||
Namespace: args.Namespace,
|
||||
Labels: map[string]string{
|
||||
createdByLabel: "yes",
|
||||
},
|
||||
},
|
||||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce},
|
||||
StorageClassName: &args.StorageClass,
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceStorage: resource.MustParse("1Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if args.DataSource != nil {
|
||||
pvc.Spec.DataSource = args.DataSource
|
||||
}
|
||||
|
||||
if args.RestoreSize != nil && !args.RestoreSize.IsZero() {
|
||||
pvc.Spec.Resources.Requests[v1.ResourceStorage] = *args.RestoreSize
|
||||
}
|
||||
|
||||
pvcRes, err := c.kubeCli.CoreV1().PersistentVolumeClaims(args.Namespace).Create(ctx, pvc, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return pvc, err
|
||||
}
|
||||
|
||||
return pvcRes, nil
|
||||
}
|
||||
|
||||
func (c *applicationCreate) CreatePod(ctx context.Context, args *types.CreatePodArgs) (*v1.Pod, error) {
|
||||
if c.kubeCli == nil {
|
||||
return nil, fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
if err := args.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.ContainerImage == "" {
|
||||
args.ContainerImage = common.DefaultPodImage
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: args.GenerateName,
|
||||
Namespace: args.Namespace,
|
||||
Labels: map[string]string{
|
||||
createdByLabel: "yes",
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{{
|
||||
Name: args.GenerateName,
|
||||
Image: args.ContainerImage,
|
||||
Command: args.Command,
|
||||
Args: args.ContainerArgs,
|
||||
VolumeMounts: []v1.VolumeMount{{
|
||||
Name: "persistent-storage",
|
||||
MountPath: args.MountPath,
|
||||
}},
|
||||
}},
|
||||
Volumes: []v1.Volume{{
|
||||
Name: "persistent-storage",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
|
||||
ClaimName: args.PVCName,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if args.RunAsUser > 0 {
|
||||
pod.Spec.SecurityContext = &v1.PodSecurityContext{
|
||||
RunAsUser: &args.RunAsUser,
|
||||
FSGroup: &args.RunAsUser,
|
||||
}
|
||||
}
|
||||
|
||||
podRes, err := c.kubeCli.CoreV1().Pods(args.Namespace).Create(ctx, pod, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return pod, err
|
||||
}
|
||||
return podRes, nil
|
||||
}
|
||||
|
||||
func (c *applicationCreate) WaitForPodReady(ctx context.Context, namespace string, podName string) error {
|
||||
if c.kubeCli == nil {
|
||||
return fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
err := kankube.WaitForPodReady(ctx, c.kubeCli, namespace, podName)
|
||||
return err
|
||||
}
|
||||
|
||||
//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_snapshot_creator.go -package=mocks . SnapshotCreator
|
||||
type SnapshotCreator interface {
|
||||
NewSnapshotter() (kansnapshot.Snapshotter, error)
|
||||
CreateSnapshot(ctx context.Context, snapshotter kansnapshot.Snapshotter, args *types.CreateSnapshotArgs) (*snapv1.VolumeSnapshot, error)
|
||||
CreateFromSourceCheck(ctx context.Context, snapshotter kansnapshot.Snapshotter, args *types.CreateFromSourceCheckArgs, SnapshotGroupVersion *metav1.GroupVersionForDiscovery) error
|
||||
}
|
||||
|
||||
type snapshotCreate struct {
|
||||
kubeCli kubernetes.Interface
|
||||
dynCli dynamic.Interface
|
||||
}
|
||||
|
||||
func (c *snapshotCreate) NewSnapshotter() (kansnapshot.Snapshotter, error) {
|
||||
if c.kubeCli == nil {
|
||||
return nil, fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
if c.dynCli == nil {
|
||||
return nil, fmt.Errorf("dynCli not initialized")
|
||||
}
|
||||
return kansnapshot.NewSnapshotter(c.kubeCli, c.dynCli)
|
||||
}
|
||||
|
||||
func (c *snapshotCreate) CreateSnapshot(ctx context.Context, snapshotter kansnapshot.Snapshotter, args *types.CreateSnapshotArgs) (*snapv1.VolumeSnapshot, error) {
|
||||
if snapshotter == nil || args == nil {
|
||||
return nil, fmt.Errorf("snapshotter or args are empty")
|
||||
}
|
||||
if err := args.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err := snapshotter.Create(ctx, args.SnapshotName, args.Namespace, args.PVCName, &args.VolumeSnapshotClass, true, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "CSI Driver failed to create snapshot for PVC (%s) in Namespace (%s)", args.PVCName, args.Namespace)
|
||||
}
|
||||
snap, err := snapshotter.Get(ctx, args.SnapshotName, args.Namespace)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to get CSI snapshot (%s) in Namespace (%s)", args.SnapshotName, args.Namespace)
|
||||
}
|
||||
return snap, nil
|
||||
}
|
||||
|
||||
func (c *snapshotCreate) CreateFromSourceCheck(ctx context.Context, snapshotter kansnapshot.Snapshotter, args *types.CreateFromSourceCheckArgs, SnapshotGroupVersion *metav1.GroupVersionForDiscovery) error {
|
||||
if c.dynCli == nil {
|
||||
return fmt.Errorf("dynCli not initialized")
|
||||
}
|
||||
if SnapshotGroupVersion == nil || SnapshotGroupVersion.Version == "" {
|
||||
return fmt.Errorf("snapshot group version not provided")
|
||||
}
|
||||
if snapshotter == nil || args == nil {
|
||||
return fmt.Errorf("snapshotter or args are nil")
|
||||
}
|
||||
if err := args.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
targetSnapClassName := clonePrefix + args.VolumeSnapshotClass
|
||||
err := snapshotter.CloneVolumeSnapshotClass(ctx, args.VolumeSnapshotClass, targetSnapClassName, kansnapshot.DeletionPolicyRetain, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Failed to clone a VolumeSnapshotClass to use to restore the snapshot")
|
||||
}
|
||||
defer func() {
|
||||
VolSnapClassGVR := schema.GroupVersionResource{Group: common.SnapGroupName, Version: SnapshotGroupVersion.Version, Resource: common.VolumeSnapshotClassResourcePlural}
|
||||
err := c.dynCli.Resource(VolSnapClassGVR).Delete(ctx, targetSnapClassName, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
fmt.Printf("Delete VSC Error (%s) - (%v)\n", targetSnapClassName, err)
|
||||
}
|
||||
}()
|
||||
|
||||
snapSrc, err := snapshotter.GetSource(ctx, args.SnapshotName, args.Namespace)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Failed to get source snapshot source (%s)", args.SnapshotName)
|
||||
}
|
||||
snapshotCFSCloneName := clonePrefix + args.SnapshotName
|
||||
// test the CreateFromSource API
|
||||
defer func() {
|
||||
_, _ = snapshotter.Delete(context.Background(), snapshotCFSCloneName, args.Namespace)
|
||||
}()
|
||||
src := &kansnapshot.Source{
|
||||
Handle: snapSrc.Handle,
|
||||
Driver: snapSrc.Driver,
|
||||
VolumeSnapshotClassName: targetSnapClassName,
|
||||
}
|
||||
err = snapshotter.CreateFromSource(ctx, src, snapshotCFSCloneName, args.Namespace, true)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Failed to clone snapshot from source (%s)", snapshotCFSCloneName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_cleaner.go -package=mocks . Cleaner
|
||||
type Cleaner interface {
|
||||
DeletePVC(ctx context.Context, pvcName string, namespace string) error
|
||||
DeletePod(ctx context.Context, podName string, namespace string) error
|
||||
DeleteSnapshot(ctx context.Context, snapshotName string, namespace string, SnapshotGroupVersion *metav1.GroupVersionForDiscovery) error
|
||||
}
|
||||
|
||||
type cleanse struct {
|
||||
kubeCli kubernetes.Interface
|
||||
dynCli dynamic.Interface
|
||||
}
|
||||
|
||||
func (c *cleanse) DeletePVC(ctx context.Context, pvcName string, namespace string) error {
|
||||
if c.kubeCli == nil {
|
||||
return fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
return c.kubeCli.CoreV1().PersistentVolumeClaims(namespace).Delete(ctx, pvcName, metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
func (c *cleanse) DeletePod(ctx context.Context, podName string, namespace string) error {
|
||||
if c.kubeCli == nil {
|
||||
return fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
return c.kubeCli.CoreV1().Pods(namespace).Delete(ctx, podName, metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
func (c *cleanse) DeleteSnapshot(ctx context.Context, snapshotName string, namespace string, SnapshotGroupVersion *metav1.GroupVersionForDiscovery) error {
|
||||
if c.dynCli == nil {
|
||||
return fmt.Errorf("dynCli not initialized")
|
||||
}
|
||||
if SnapshotGroupVersion == nil || SnapshotGroupVersion.Version == "" {
|
||||
return fmt.Errorf("snapshot group version not provided")
|
||||
}
|
||||
VolSnapGVR := schema.GroupVersionResource{Group: common.SnapGroupName, Version: SnapshotGroupVersion.Version, Resource: common.VolumeSnapshotResourcePlural}
|
||||
return c.dynCli.Resource(VolSnapGVR).Namespace(namespace).Delete(ctx, snapshotName, metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_api_version_fetcher.go -package=mocks . ApiVersionFetcher
|
||||
type ApiVersionFetcher interface {
|
||||
GetCSISnapshotGroupVersion() (*metav1.GroupVersionForDiscovery, error)
|
||||
}
|
||||
|
||||
type apiVersionFetch struct {
|
||||
kubeCli kubernetes.Interface
|
||||
}
|
||||
|
||||
func (p *apiVersionFetch) GetCSISnapshotGroupVersion() (*metav1.GroupVersionForDiscovery, error) {
|
||||
if p.kubeCli == nil {
|
||||
return nil, fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
groups, _, err := p.kubeCli.Discovery().ServerGroupsAndResources()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, group := range groups {
|
||||
if group.Name == common.SnapGroupName {
|
||||
return &group.PreferredVersion, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("Snapshot API group not found")
|
||||
}
|
||||
|
||||
//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_data_validator.go -package=mocks . DataValidator
|
||||
type DataValidator interface {
|
||||
FetchPodData(podName string, podNamespace string) (string, error)
|
||||
}
|
||||
|
||||
type validateData struct {
|
||||
kubeCli kubernetes.Interface
|
||||
}
|
||||
|
||||
func (p *validateData) FetchPodData(podName string, podNamespace string) (string, error) {
|
||||
if p.kubeCli == nil {
|
||||
return "", fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
stdout, _, err := kankube.Exec(p.kubeCli, podNamespace, podName, "", []string{"sh", "-c", "cat /data/out.txt"}, nil)
|
||||
return stdout, err
|
||||
}
|
||||
|
||||
//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_port_forwarder.go -package=mocks . PortForwarder
|
||||
type PortForwarder interface {
|
||||
FetchRestConfig() (*rest.Config, error)
|
||||
PortForwardAPod(req *types.PortForwardAPodRequest) error
|
||||
}
|
||||
|
||||
type portforward struct{}
|
||||
|
||||
func (p *portforward) PortForwardAPod(req *types.PortForwardAPodRequest) error {
|
||||
path := fmt.Sprintf("/api/v1/namespaces/%s/pods/%s/portforward",
|
||||
req.Pod.Namespace, req.Pod.Name)
|
||||
hostIP := strings.TrimLeft(req.RestConfig.Host, "https:/")
|
||||
|
||||
transport, upgrader, err := spdy.RoundTripperFor(req.RestConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, http.MethodPost, &url.URL{Scheme: "https", Path: path, Host: hostIP})
|
||||
fw, err := pf.New(dialer, []string{fmt.Sprintf("%d:%d", req.LocalPort, req.PodPort)}, req.StopCh, req.ReadyCh, &req.OutStream, &req.ErrOutStream)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fw.ForwardPorts()
|
||||
}
|
||||
|
||||
func (p *portforward) FetchRestConfig() (*rest.Config, error) {
|
||||
return kube.LoadConfig()
|
||||
}
|
|
@ -474,7 +474,7 @@ func (s *CSITestSuite) TestCreatePod(c *C) {
|
|||
GenerateName: "name",
|
||||
PVCName: "pvcname",
|
||||
Namespace: "ns",
|
||||
Cmd: "somecommand",
|
||||
Command: []string{"somecommand"},
|
||||
RunAsUser: 1000,
|
||||
ContainerImage: "containerimage",
|
||||
},
|
||||
|
@ -487,7 +487,7 @@ func (s *CSITestSuite) TestCreatePod(c *C) {
|
|||
GenerateName: "name",
|
||||
PVCName: "pvcname",
|
||||
Namespace: "ns",
|
||||
Cmd: "somecommand",
|
||||
Command: []string{"somecommand"},
|
||||
},
|
||||
errChecker: IsNil,
|
||||
podChecker: NotNil,
|
||||
|
@ -498,7 +498,7 @@ func (s *CSITestSuite) TestCreatePod(c *C) {
|
|||
GenerateName: "name",
|
||||
PVCName: "pvcname",
|
||||
Namespace: "ns",
|
||||
Cmd: "somecommand",
|
||||
Command: []string{"somecommand"},
|
||||
},
|
||||
failCreates: true,
|
||||
errChecker: NotNil,
|
||||
|
@ -510,7 +510,7 @@ func (s *CSITestSuite) TestCreatePod(c *C) {
|
|||
GenerateName: "",
|
||||
PVCName: "pvcname",
|
||||
Namespace: "ns",
|
||||
Cmd: "somecommand",
|
||||
Command: []string{"somecommand"},
|
||||
},
|
||||
errChecker: NotNil,
|
||||
podChecker: IsNil,
|
||||
|
@ -521,7 +521,7 @@ func (s *CSITestSuite) TestCreatePod(c *C) {
|
|||
GenerateName: "name",
|
||||
PVCName: "",
|
||||
Namespace: "ns",
|
||||
Cmd: "somecommand",
|
||||
Command: []string{"somecommand"},
|
||||
},
|
||||
errChecker: NotNil,
|
||||
podChecker: IsNil,
|
||||
|
@ -532,7 +532,7 @@ func (s *CSITestSuite) TestCreatePod(c *C) {
|
|||
GenerateName: "name",
|
||||
PVCName: "pvcname",
|
||||
Namespace: "",
|
||||
Cmd: "somecommand",
|
||||
Command: []string{"somecommand"},
|
||||
},
|
||||
errChecker: NotNil,
|
||||
podChecker: IsNil,
|
||||
|
@ -543,10 +543,10 @@ func (s *CSITestSuite) TestCreatePod(c *C) {
|
|||
GenerateName: "name",
|
||||
PVCName: "pvcname",
|
||||
Namespace: "ns",
|
||||
Cmd: "",
|
||||
Command: []string{"somecommand"},
|
||||
},
|
||||
errChecker: NotNil,
|
||||
podChecker: IsNil,
|
||||
errChecker: IsNil,
|
||||
podChecker: NotNil,
|
||||
},
|
||||
{
|
||||
cli: nil,
|
||||
|
@ -571,11 +571,11 @@ func (s *CSITestSuite) TestCreatePod(c *C) {
|
|||
c.Assert(pod.Namespace, Equals, tc.args.Namespace)
|
||||
c.Assert(len(pod.Spec.Containers), Equals, 1)
|
||||
c.Assert(pod.Spec.Containers[0].Name, Equals, tc.args.GenerateName)
|
||||
c.Assert(pod.Spec.Containers[0].Command, DeepEquals, []string{"/bin/sh"})
|
||||
c.Assert(pod.Spec.Containers[0].Args, DeepEquals, []string{"-c", tc.args.Cmd})
|
||||
c.Assert(pod.Spec.Containers[0].Command, DeepEquals, tc.args.Command)
|
||||
c.Assert(pod.Spec.Containers[0].Args, DeepEquals, tc.args.ContainerArgs)
|
||||
c.Assert(pod.Spec.Containers[0].VolumeMounts, DeepEquals, []v1.VolumeMount{{
|
||||
Name: "persistent-storage",
|
||||
MountPath: "/data",
|
||||
MountPath: tc.args.MountPath,
|
||||
}})
|
||||
c.Assert(pod.Spec.Volumes, DeepEquals, []v1.Volume{{
|
||||
Name: "persistent-storage",
|
|
@ -5,35 +5,36 @@
|
|||
package mocks
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockApiVersionFetcher is a mock of ApiVersionFetcher interface
|
||||
// MockApiVersionFetcher is a mock of ApiVersionFetcher interface.
|
||||
type MockApiVersionFetcher struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockApiVersionFetcherMockRecorder
|
||||
}
|
||||
|
||||
// MockApiVersionFetcherMockRecorder is the mock recorder for MockApiVersionFetcher
|
||||
// MockApiVersionFetcherMockRecorder is the mock recorder for MockApiVersionFetcher.
|
||||
type MockApiVersionFetcherMockRecorder struct {
|
||||
mock *MockApiVersionFetcher
|
||||
}
|
||||
|
||||
// NewMockApiVersionFetcher creates a new mock instance
|
||||
// NewMockApiVersionFetcher creates a new mock instance.
|
||||
func NewMockApiVersionFetcher(ctrl *gomock.Controller) *MockApiVersionFetcher {
|
||||
mock := &MockApiVersionFetcher{ctrl: ctrl}
|
||||
mock.recorder = &MockApiVersionFetcherMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockApiVersionFetcher) EXPECT() *MockApiVersionFetcherMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// GetCSISnapshotGroupVersion mocks base method
|
||||
// GetCSISnapshotGroupVersion mocks base method.
|
||||
func (m *MockApiVersionFetcher) GetCSISnapshotGroupVersion() (*v1.GroupVersionForDiscovery, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetCSISnapshotGroupVersion")
|
||||
|
@ -42,7 +43,7 @@ func (m *MockApiVersionFetcher) GetCSISnapshotGroupVersion() (*v1.GroupVersionFo
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetCSISnapshotGroupVersion indicates an expected call of GetCSISnapshotGroupVersion
|
||||
// GetCSISnapshotGroupVersion indicates an expected call of GetCSISnapshotGroupVersion.
|
||||
func (mr *MockApiVersionFetcherMockRecorder) GetCSISnapshotGroupVersion() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCSISnapshotGroupVersion", reflect.TypeOf((*MockApiVersionFetcher)(nil).GetCSISnapshotGroupVersion))
|
||||
|
|
|
@ -6,36 +6,37 @@ package mocks
|
|||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
types "github.com/kastenhq/kubestr/pkg/csi/types"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockApplicationCreator is a mock of ApplicationCreator interface
|
||||
// MockApplicationCreator is a mock of ApplicationCreator interface.
|
||||
type MockApplicationCreator struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockApplicationCreatorMockRecorder
|
||||
}
|
||||
|
||||
// MockApplicationCreatorMockRecorder is the mock recorder for MockApplicationCreator
|
||||
// MockApplicationCreatorMockRecorder is the mock recorder for MockApplicationCreator.
|
||||
type MockApplicationCreatorMockRecorder struct {
|
||||
mock *MockApplicationCreator
|
||||
}
|
||||
|
||||
// NewMockApplicationCreator creates a new mock instance
|
||||
// NewMockApplicationCreator creates a new mock instance.
|
||||
func NewMockApplicationCreator(ctrl *gomock.Controller) *MockApplicationCreator {
|
||||
mock := &MockApplicationCreator{ctrl: ctrl}
|
||||
mock.recorder = &MockApplicationCreatorMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockApplicationCreator) EXPECT() *MockApplicationCreatorMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// CreatePVC mocks base method
|
||||
// CreatePVC mocks base method.
|
||||
func (m *MockApplicationCreator) CreatePVC(arg0 context.Context, arg1 *types.CreatePVCArgs) (*v1.PersistentVolumeClaim, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreatePVC", arg0, arg1)
|
||||
|
@ -44,13 +45,13 @@ func (m *MockApplicationCreator) CreatePVC(arg0 context.Context, arg1 *types.Cre
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreatePVC indicates an expected call of CreatePVC
|
||||
// CreatePVC indicates an expected call of CreatePVC.
|
||||
func (mr *MockApplicationCreatorMockRecorder) CreatePVC(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePVC", reflect.TypeOf((*MockApplicationCreator)(nil).CreatePVC), arg0, arg1)
|
||||
}
|
||||
|
||||
// CreatePod mocks base method
|
||||
// CreatePod mocks base method.
|
||||
func (m *MockApplicationCreator) CreatePod(arg0 context.Context, arg1 *types.CreatePodArgs) (*v1.Pod, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreatePod", arg0, arg1)
|
||||
|
@ -59,13 +60,13 @@ func (m *MockApplicationCreator) CreatePod(arg0 context.Context, arg1 *types.Cre
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreatePod indicates an expected call of CreatePod
|
||||
// CreatePod indicates an expected call of CreatePod.
|
||||
func (mr *MockApplicationCreatorMockRecorder) CreatePod(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePod", reflect.TypeOf((*MockApplicationCreator)(nil).CreatePod), arg0, arg1)
|
||||
}
|
||||
|
||||
// WaitForPodReady mocks base method
|
||||
// WaitForPodReady mocks base method.
|
||||
func (m *MockApplicationCreator) WaitForPodReady(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "WaitForPodReady", arg0, arg1, arg2)
|
||||
|
@ -73,7 +74,7 @@ func (m *MockApplicationCreator) WaitForPodReady(arg0 context.Context, arg1, arg
|
|||
return ret0
|
||||
}
|
||||
|
||||
// WaitForPodReady indicates an expected call of WaitForPodReady
|
||||
// WaitForPodReady indicates an expected call of WaitForPodReady.
|
||||
func (mr *MockApplicationCreatorMockRecorder) WaitForPodReady(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForPodReady", reflect.TypeOf((*MockApplicationCreator)(nil).WaitForPodReady), arg0, arg1, arg2)
|
||||
|
|
|
@ -6,37 +6,54 @@ package mocks
|
|||
|
||||
import (
|
||||
context "context"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
v1 "k8s.io/api/storage/v1"
|
||||
v10 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
v10 "k8s.io/api/storage/v1"
|
||||
v11 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
// MockArgumentValidator is a mock of ArgumentValidator interface
|
||||
// MockArgumentValidator is a mock of ArgumentValidator interface.
|
||||
type MockArgumentValidator struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockArgumentValidatorMockRecorder
|
||||
}
|
||||
|
||||
// MockArgumentValidatorMockRecorder is the mock recorder for MockArgumentValidator
|
||||
// MockArgumentValidatorMockRecorder is the mock recorder for MockArgumentValidator.
|
||||
type MockArgumentValidatorMockRecorder struct {
|
||||
mock *MockArgumentValidator
|
||||
}
|
||||
|
||||
// NewMockArgumentValidator creates a new mock instance
|
||||
// NewMockArgumentValidator creates a new mock instance.
|
||||
func NewMockArgumentValidator(ctrl *gomock.Controller) *MockArgumentValidator {
|
||||
mock := &MockArgumentValidator{ctrl: ctrl}
|
||||
mock.recorder = &MockArgumentValidatorMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockArgumentValidator) EXPECT() *MockArgumentValidatorMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// ValidateNamespace mocks base method
|
||||
// FetchPV mocks base method.
|
||||
func (m *MockArgumentValidator) FetchPV(arg0 context.Context, arg1 string) (*v1.PersistentVolume, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FetchPV", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v1.PersistentVolume)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// FetchPV indicates an expected call of FetchPV.
|
||||
func (mr *MockArgumentValidatorMockRecorder) FetchPV(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchPV", reflect.TypeOf((*MockArgumentValidator)(nil).FetchPV), arg0, arg1)
|
||||
}
|
||||
|
||||
// ValidateNamespace mocks base method.
|
||||
func (m *MockArgumentValidator) ValidateNamespace(arg0 context.Context, arg1 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ValidateNamespace", arg0, arg1)
|
||||
|
@ -44,29 +61,44 @@ func (m *MockArgumentValidator) ValidateNamespace(arg0 context.Context, arg1 str
|
|||
return ret0
|
||||
}
|
||||
|
||||
// ValidateNamespace indicates an expected call of ValidateNamespace
|
||||
// ValidateNamespace indicates an expected call of ValidateNamespace.
|
||||
func (mr *MockArgumentValidatorMockRecorder) ValidateNamespace(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateNamespace", reflect.TypeOf((*MockArgumentValidator)(nil).ValidateNamespace), arg0, arg1)
|
||||
}
|
||||
|
||||
// ValidateStorageClass mocks base method
|
||||
func (m *MockArgumentValidator) ValidateStorageClass(arg0 context.Context, arg1 string) (*v1.StorageClass, error) {
|
||||
// ValidatePVC mocks base method.
|
||||
func (m *MockArgumentValidator) ValidatePVC(arg0 context.Context, arg1, arg2 string) (*v1.PersistentVolumeClaim, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ValidateStorageClass", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v1.StorageClass)
|
||||
ret := m.ctrl.Call(m, "ValidatePVC", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*v1.PersistentVolumeClaim)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ValidateStorageClass indicates an expected call of ValidateStorageClass
|
||||
// ValidatePVC indicates an expected call of ValidatePVC.
|
||||
func (mr *MockArgumentValidatorMockRecorder) ValidatePVC(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatePVC", reflect.TypeOf((*MockArgumentValidator)(nil).ValidatePVC), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// ValidateStorageClass mocks base method.
|
||||
func (m *MockArgumentValidator) ValidateStorageClass(arg0 context.Context, arg1 string) (*v10.StorageClass, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ValidateStorageClass", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v10.StorageClass)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ValidateStorageClass indicates an expected call of ValidateStorageClass.
|
||||
func (mr *MockArgumentValidatorMockRecorder) ValidateStorageClass(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateStorageClass", reflect.TypeOf((*MockArgumentValidator)(nil).ValidateStorageClass), arg0, arg1)
|
||||
}
|
||||
|
||||
// ValidateVolumeSnapshotClass mocks base method
|
||||
func (m *MockArgumentValidator) ValidateVolumeSnapshotClass(arg0 context.Context, arg1 string, arg2 *v10.GroupVersionForDiscovery) (*unstructured.Unstructured, error) {
|
||||
// ValidateVolumeSnapshotClass mocks base method.
|
||||
func (m *MockArgumentValidator) ValidateVolumeSnapshotClass(arg0 context.Context, arg1 string, arg2 *v11.GroupVersionForDiscovery) (*unstructured.Unstructured, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ValidateVolumeSnapshotClass", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*unstructured.Unstructured)
|
||||
|
@ -74,7 +106,7 @@ func (m *MockArgumentValidator) ValidateVolumeSnapshotClass(arg0 context.Context
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ValidateVolumeSnapshotClass indicates an expected call of ValidateVolumeSnapshotClass
|
||||
// ValidateVolumeSnapshotClass indicates an expected call of ValidateVolumeSnapshotClass.
|
||||
func (mr *MockArgumentValidatorMockRecorder) ValidateVolumeSnapshotClass(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateVolumeSnapshotClass", reflect.TypeOf((*MockArgumentValidator)(nil).ValidateVolumeSnapshotClass), arg0, arg1, arg2)
|
||||
|
|
|
@ -6,35 +6,36 @@ package mocks
|
|||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockCleaner is a mock of Cleaner interface
|
||||
// MockCleaner is a mock of Cleaner interface.
|
||||
type MockCleaner struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockCleanerMockRecorder
|
||||
}
|
||||
|
||||
// MockCleanerMockRecorder is the mock recorder for MockCleaner
|
||||
// MockCleanerMockRecorder is the mock recorder for MockCleaner.
|
||||
type MockCleanerMockRecorder struct {
|
||||
mock *MockCleaner
|
||||
}
|
||||
|
||||
// NewMockCleaner creates a new mock instance
|
||||
// NewMockCleaner creates a new mock instance.
|
||||
func NewMockCleaner(ctrl *gomock.Controller) *MockCleaner {
|
||||
mock := &MockCleaner{ctrl: ctrl}
|
||||
mock.recorder = &MockCleanerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockCleaner) EXPECT() *MockCleanerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// DeletePVC mocks base method
|
||||
// DeletePVC mocks base method.
|
||||
func (m *MockCleaner) DeletePVC(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeletePVC", arg0, arg1, arg2)
|
||||
|
@ -42,13 +43,13 @@ func (m *MockCleaner) DeletePVC(arg0 context.Context, arg1, arg2 string) error {
|
|||
return ret0
|
||||
}
|
||||
|
||||
// DeletePVC indicates an expected call of DeletePVC
|
||||
// DeletePVC indicates an expected call of DeletePVC.
|
||||
func (mr *MockCleanerMockRecorder) DeletePVC(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePVC", reflect.TypeOf((*MockCleaner)(nil).DeletePVC), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// DeletePod mocks base method
|
||||
// DeletePod mocks base method.
|
||||
func (m *MockCleaner) DeletePod(arg0 context.Context, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeletePod", arg0, arg1, arg2)
|
||||
|
@ -56,13 +57,13 @@ func (m *MockCleaner) DeletePod(arg0 context.Context, arg1, arg2 string) error {
|
|||
return ret0
|
||||
}
|
||||
|
||||
// DeletePod indicates an expected call of DeletePod
|
||||
// DeletePod indicates an expected call of DeletePod.
|
||||
func (mr *MockCleanerMockRecorder) DeletePod(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePod", reflect.TypeOf((*MockCleaner)(nil).DeletePod), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// DeleteSnapshot mocks base method
|
||||
// DeleteSnapshot mocks base method.
|
||||
func (m *MockCleaner) DeleteSnapshot(arg0 context.Context, arg1, arg2 string, arg3 *v1.GroupVersionForDiscovery) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteSnapshot", arg0, arg1, arg2, arg3)
|
||||
|
@ -70,7 +71,7 @@ func (m *MockCleaner) DeleteSnapshot(arg0 context.Context, arg1, arg2 string, ar
|
|||
return ret0
|
||||
}
|
||||
|
||||
// DeleteSnapshot indicates an expected call of DeleteSnapshot
|
||||
// DeleteSnapshot indicates an expected call of DeleteSnapshot.
|
||||
func (mr *MockCleanerMockRecorder) DeleteSnapshot(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSnapshot", reflect.TypeOf((*MockCleaner)(nil).DeleteSnapshot), arg0, arg1, arg2, arg3)
|
||||
|
|
|
@ -5,34 +5,35 @@
|
|||
package mocks
|
||||
|
||||
import (
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockDataValidator is a mock of DataValidator interface
|
||||
// MockDataValidator is a mock of DataValidator interface.
|
||||
type MockDataValidator struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockDataValidatorMockRecorder
|
||||
}
|
||||
|
||||
// MockDataValidatorMockRecorder is the mock recorder for MockDataValidator
|
||||
// MockDataValidatorMockRecorder is the mock recorder for MockDataValidator.
|
||||
type MockDataValidatorMockRecorder struct {
|
||||
mock *MockDataValidator
|
||||
}
|
||||
|
||||
// NewMockDataValidator creates a new mock instance
|
||||
// NewMockDataValidator creates a new mock instance.
|
||||
func NewMockDataValidator(ctrl *gomock.Controller) *MockDataValidator {
|
||||
mock := &MockDataValidator{ctrl: ctrl}
|
||||
mock.recorder = &MockDataValidatorMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockDataValidator) EXPECT() *MockDataValidatorMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// FetchPodData mocks base method
|
||||
// FetchPodData mocks base method.
|
||||
func (m *MockDataValidator) FetchPodData(arg0, arg1 string) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FetchPodData", arg0, arg1)
|
||||
|
@ -41,7 +42,7 @@ func (m *MockDataValidator) FetchPodData(arg0, arg1 string) (string, error) {
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// FetchPodData indicates an expected call of FetchPodData
|
||||
// FetchPodData indicates an expected call of FetchPodData.
|
||||
func (mr *MockDataValidatorMockRecorder) FetchPodData(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchPodData", reflect.TypeOf((*MockDataValidator)(nil).FetchPodData), arg0, arg1)
|
||||
|
|
65
pkg/csi/mocks/mock_port_forwarder.go
Normal file
65
pkg/csi/mocks/mock_port_forwarder.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/kastenhq/kubestr/pkg/csi (interfaces: PortForwarder)
|
||||
|
||||
// Package mocks is a generated GoMock package.
|
||||
package mocks
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
types "github.com/kastenhq/kubestr/pkg/csi/types"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// MockPortForwarder is a mock of PortForwarder interface.
|
||||
type MockPortForwarder struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockPortForwarderMockRecorder
|
||||
}
|
||||
|
||||
// MockPortForwarderMockRecorder is the mock recorder for MockPortForwarder.
|
||||
type MockPortForwarderMockRecorder struct {
|
||||
mock *MockPortForwarder
|
||||
}
|
||||
|
||||
// NewMockPortForwarder creates a new mock instance.
|
||||
func NewMockPortForwarder(ctrl *gomock.Controller) *MockPortForwarder {
|
||||
mock := &MockPortForwarder{ctrl: ctrl}
|
||||
mock.recorder = &MockPortForwarderMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockPortForwarder) EXPECT() *MockPortForwarderMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// FetchRestConfig mocks base method.
|
||||
func (m *MockPortForwarder) FetchRestConfig() (*rest.Config, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FetchRestConfig")
|
||||
ret0, _ := ret[0].(*rest.Config)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// FetchRestConfig indicates an expected call of FetchRestConfig.
|
||||
func (mr *MockPortForwarderMockRecorder) FetchRestConfig() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchRestConfig", reflect.TypeOf((*MockPortForwarder)(nil).FetchRestConfig))
|
||||
}
|
||||
|
||||
// PortForwardAPod mocks base method.
|
||||
func (m *MockPortForwarder) PortForwardAPod(arg0 *types.PortForwardAPodRequest) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PortForwardAPod", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// PortForwardAPod indicates an expected call of PortForwardAPod.
|
||||
func (mr *MockPortForwarderMockRecorder) PortForwardAPod(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PortForwardAPod", reflect.TypeOf((*MockPortForwarder)(nil).PortForwardAPod), arg0)
|
||||
}
|
111
pkg/csi/mocks/mock_pvc_browser_stepper.go
Normal file
111
pkg/csi/mocks/mock_pvc_browser_stepper.go
Normal file
|
@ -0,0 +1,111 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/kastenhq/kubestr/pkg/csi (interfaces: PVCBrowserStepper)
|
||||
|
||||
// Package mocks is a generated GoMock package.
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
types "github.com/kastenhq/kubestr/pkg/csi/types"
|
||||
v1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
v10 "k8s.io/api/core/v1"
|
||||
v11 "k8s.io/api/storage/v1"
|
||||
)
|
||||
|
||||
// MockPVCBrowserStepper is a mock of PVCBrowserStepper interface.
|
||||
type MockPVCBrowserStepper struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockPVCBrowserStepperMockRecorder
|
||||
}
|
||||
|
||||
// MockPVCBrowserStepperMockRecorder is the mock recorder for MockPVCBrowserStepper.
|
||||
type MockPVCBrowserStepperMockRecorder struct {
|
||||
mock *MockPVCBrowserStepper
|
||||
}
|
||||
|
||||
// NewMockPVCBrowserStepper creates a new mock instance.
|
||||
func NewMockPVCBrowserStepper(ctrl *gomock.Controller) *MockPVCBrowserStepper {
|
||||
mock := &MockPVCBrowserStepper{ctrl: ctrl}
|
||||
mock.recorder = &MockPVCBrowserStepperMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockPVCBrowserStepper) EXPECT() *MockPVCBrowserStepperMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Cleanup mocks base method.
|
||||
func (m *MockPVCBrowserStepper) Cleanup(arg0 context.Context, arg1 *v10.PersistentVolumeClaim, arg2 *v10.Pod, arg3 *v1.VolumeSnapshot) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Cleanup", arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// Cleanup indicates an expected call of Cleanup.
|
||||
func (mr *MockPVCBrowserStepperMockRecorder) Cleanup(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Cleanup", reflect.TypeOf((*MockPVCBrowserStepper)(nil).Cleanup), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// CreateInspectorApplication mocks base method.
|
||||
func (m *MockPVCBrowserStepper) CreateInspectorApplication(arg0 context.Context, arg1 *types.PVCBrowseArgs, arg2 *v1.VolumeSnapshot, arg3 *v11.StorageClass) (*v10.Pod, *v10.PersistentVolumeClaim, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateInspectorApplication", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(*v10.Pod)
|
||||
ret1, _ := ret[1].(*v10.PersistentVolumeClaim)
|
||||
ret2, _ := ret[2].(error)
|
||||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// CreateInspectorApplication indicates an expected call of CreateInspectorApplication.
|
||||
func (mr *MockPVCBrowserStepperMockRecorder) CreateInspectorApplication(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateInspectorApplication", reflect.TypeOf((*MockPVCBrowserStepper)(nil).CreateInspectorApplication), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// PortForwardAPod mocks base method.
|
||||
func (m *MockPVCBrowserStepper) PortForwardAPod(arg0 context.Context, arg1 *v10.Pod, arg2 int) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PortForwardAPod", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// PortForwardAPod indicates an expected call of PortForwardAPod.
|
||||
func (mr *MockPVCBrowserStepperMockRecorder) PortForwardAPod(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PortForwardAPod", reflect.TypeOf((*MockPVCBrowserStepper)(nil).PortForwardAPod), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// SnapshotPVC mocks base method.
|
||||
func (m *MockPVCBrowserStepper) SnapshotPVC(arg0 context.Context, arg1 *types.PVCBrowseArgs, arg2 string) (*v1.VolumeSnapshot, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SnapshotPVC", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*v1.VolumeSnapshot)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SnapshotPVC indicates an expected call of SnapshotPVC.
|
||||
func (mr *MockPVCBrowserStepperMockRecorder) SnapshotPVC(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SnapshotPVC", reflect.TypeOf((*MockPVCBrowserStepper)(nil).SnapshotPVC), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// ValidateArgs mocks base method.
|
||||
func (m *MockPVCBrowserStepper) ValidateArgs(arg0 context.Context, arg1 *types.PVCBrowseArgs) (*v11.StorageClass, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ValidateArgs", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v11.StorageClass)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ValidateArgs indicates an expected call of ValidateArgs.
|
||||
func (mr *MockPVCBrowserStepperMockRecorder) ValidateArgs(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateArgs", reflect.TypeOf((*MockPVCBrowserStepper)(nil).ValidateArgs), arg0, arg1)
|
||||
}
|
|
@ -6,67 +6,68 @@ package mocks
|
|||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
snapshot "github.com/kanisterio/kanister/pkg/kube/snapshot"
|
||||
types "github.com/kastenhq/kubestr/pkg/csi/types"
|
||||
snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
reflect "reflect"
|
||||
v1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
v10 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// MockSnapshotCreator is a mock of SnapshotCreator interface
|
||||
// MockSnapshotCreator is a mock of SnapshotCreator interface.
|
||||
type MockSnapshotCreator struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSnapshotCreatorMockRecorder
|
||||
}
|
||||
|
||||
// MockSnapshotCreatorMockRecorder is the mock recorder for MockSnapshotCreator
|
||||
// MockSnapshotCreatorMockRecorder is the mock recorder for MockSnapshotCreator.
|
||||
type MockSnapshotCreatorMockRecorder struct {
|
||||
mock *MockSnapshotCreator
|
||||
}
|
||||
|
||||
// NewMockSnapshotCreator creates a new mock instance
|
||||
// NewMockSnapshotCreator creates a new mock instance.
|
||||
func NewMockSnapshotCreator(ctrl *gomock.Controller) *MockSnapshotCreator {
|
||||
mock := &MockSnapshotCreator{ctrl: ctrl}
|
||||
mock.recorder = &MockSnapshotCreatorMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockSnapshotCreator) EXPECT() *MockSnapshotCreatorMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// CreateFromSourceCheck mocks base method
|
||||
func (m *MockSnapshotCreator) CreateFromSourceCheck(arg0 context.Context, arg1 snapshot.Snapshotter, arg2 *types.CreateFromSourceCheckArgs, arg3 *v1.GroupVersionForDiscovery) error {
|
||||
// CreateFromSourceCheck mocks base method.
|
||||
func (m *MockSnapshotCreator) CreateFromSourceCheck(arg0 context.Context, arg1 snapshot.Snapshotter, arg2 *types.CreateFromSourceCheckArgs, arg3 *v10.GroupVersionForDiscovery) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateFromSourceCheck", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// CreateFromSourceCheck indicates an expected call of CreateFromSourceCheck
|
||||
// CreateFromSourceCheck indicates an expected call of CreateFromSourceCheck.
|
||||
func (mr *MockSnapshotCreatorMockRecorder) CreateFromSourceCheck(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFromSourceCheck", reflect.TypeOf((*MockSnapshotCreator)(nil).CreateFromSourceCheck), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// CreateSnapshot mocks base method
|
||||
func (m *MockSnapshotCreator) CreateSnapshot(arg0 context.Context, arg1 snapshot.Snapshotter, arg2 *types.CreateSnapshotArgs) (*snapv1.VolumeSnapshot, error) {
|
||||
// CreateSnapshot mocks base method.
|
||||
func (m *MockSnapshotCreator) CreateSnapshot(arg0 context.Context, arg1 snapshot.Snapshotter, arg2 *types.CreateSnapshotArgs) (*v1.VolumeSnapshot, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateSnapshot", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*snapv1.VolumeSnapshot)
|
||||
ret0, _ := ret[0].(*v1.VolumeSnapshot)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateSnapshot indicates an expected call of CreateSnapshot
|
||||
// CreateSnapshot indicates an expected call of CreateSnapshot.
|
||||
func (mr *MockSnapshotCreatorMockRecorder) CreateSnapshot(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSnapshot", reflect.TypeOf((*MockSnapshotCreator)(nil).CreateSnapshot), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// NewSnapshotter mocks base method
|
||||
// NewSnapshotter mocks base method.
|
||||
func (m *MockSnapshotCreator) NewSnapshotter() (snapshot.Snapshotter, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "NewSnapshotter")
|
||||
|
@ -75,7 +76,7 @@ func (m *MockSnapshotCreator) NewSnapshotter() (snapshot.Snapshotter, error) {
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// NewSnapshotter indicates an expected call of NewSnapshotter
|
||||
// NewSnapshotter indicates an expected call of NewSnapshotter.
|
||||
func (mr *MockSnapshotCreatorMockRecorder) NewSnapshotter() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewSnapshotter", reflect.TypeOf((*MockSnapshotCreator)(nil).NewSnapshotter))
|
||||
|
|
|
@ -6,96 +6,97 @@ package mocks
|
|||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
types "github.com/kastenhq/kubestr/pkg/csi/types"
|
||||
snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
reflect "reflect"
|
||||
v1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
v10 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// MockSnapshotRestoreStepper is a mock of SnapshotRestoreStepper interface
|
||||
// MockSnapshotRestoreStepper is a mock of SnapshotRestoreStepper interface.
|
||||
type MockSnapshotRestoreStepper struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSnapshotRestoreStepperMockRecorder
|
||||
}
|
||||
|
||||
// MockSnapshotRestoreStepperMockRecorder is the mock recorder for MockSnapshotRestoreStepper
|
||||
// MockSnapshotRestoreStepperMockRecorder is the mock recorder for MockSnapshotRestoreStepper.
|
||||
type MockSnapshotRestoreStepperMockRecorder struct {
|
||||
mock *MockSnapshotRestoreStepper
|
||||
}
|
||||
|
||||
// NewMockSnapshotRestoreStepper creates a new mock instance
|
||||
// NewMockSnapshotRestoreStepper creates a new mock instance.
|
||||
func NewMockSnapshotRestoreStepper(ctrl *gomock.Controller) *MockSnapshotRestoreStepper {
|
||||
mock := &MockSnapshotRestoreStepper{ctrl: ctrl}
|
||||
mock.recorder = &MockSnapshotRestoreStepperMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockSnapshotRestoreStepper) EXPECT() *MockSnapshotRestoreStepperMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Cleanup mocks base method
|
||||
// Cleanup mocks base method.
|
||||
func (m *MockSnapshotRestoreStepper) Cleanup(arg0 context.Context, arg1 *types.CSISnapshotRestoreResults) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Cleanup", arg0, arg1)
|
||||
}
|
||||
|
||||
// Cleanup indicates an expected call of Cleanup
|
||||
// Cleanup indicates an expected call of Cleanup.
|
||||
func (mr *MockSnapshotRestoreStepperMockRecorder) Cleanup(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Cleanup", reflect.TypeOf((*MockSnapshotRestoreStepper)(nil).Cleanup), arg0, arg1)
|
||||
}
|
||||
|
||||
// CreateApplication mocks base method
|
||||
func (m *MockSnapshotRestoreStepper) CreateApplication(arg0 context.Context, arg1 *types.CSISnapshotRestoreArgs, arg2 string) (*v1.Pod, *v1.PersistentVolumeClaim, error) {
|
||||
// CreateApplication mocks base method.
|
||||
func (m *MockSnapshotRestoreStepper) CreateApplication(arg0 context.Context, arg1 *types.CSISnapshotRestoreArgs, arg2 string) (*v10.Pod, *v10.PersistentVolumeClaim, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateApplication", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*v1.Pod)
|
||||
ret1, _ := ret[1].(*v1.PersistentVolumeClaim)
|
||||
ret0, _ := ret[0].(*v10.Pod)
|
||||
ret1, _ := ret[1].(*v10.PersistentVolumeClaim)
|
||||
ret2, _ := ret[2].(error)
|
||||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// CreateApplication indicates an expected call of CreateApplication
|
||||
// CreateApplication indicates an expected call of CreateApplication.
|
||||
func (mr *MockSnapshotRestoreStepperMockRecorder) CreateApplication(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateApplication", reflect.TypeOf((*MockSnapshotRestoreStepper)(nil).CreateApplication), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// RestoreApplication mocks base method
|
||||
func (m *MockSnapshotRestoreStepper) RestoreApplication(arg0 context.Context, arg1 *types.CSISnapshotRestoreArgs, arg2 *snapv1.VolumeSnapshot) (*v1.Pod, *v1.PersistentVolumeClaim, error) {
|
||||
// RestoreApplication mocks base method.
|
||||
func (m *MockSnapshotRestoreStepper) RestoreApplication(arg0 context.Context, arg1 *types.CSISnapshotRestoreArgs, arg2 *v1.VolumeSnapshot) (*v10.Pod, *v10.PersistentVolumeClaim, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RestoreApplication", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*v1.Pod)
|
||||
ret1, _ := ret[1].(*v1.PersistentVolumeClaim)
|
||||
ret0, _ := ret[0].(*v10.Pod)
|
||||
ret1, _ := ret[1].(*v10.PersistentVolumeClaim)
|
||||
ret2, _ := ret[2].(error)
|
||||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// RestoreApplication indicates an expected call of RestoreApplication
|
||||
// RestoreApplication indicates an expected call of RestoreApplication.
|
||||
func (mr *MockSnapshotRestoreStepperMockRecorder) RestoreApplication(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RestoreApplication", reflect.TypeOf((*MockSnapshotRestoreStepper)(nil).RestoreApplication), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// SnapshotApplication mocks base method
|
||||
func (m *MockSnapshotRestoreStepper) SnapshotApplication(arg0 context.Context, arg1 *types.CSISnapshotRestoreArgs, arg2 *v1.PersistentVolumeClaim, arg3 string) (*snapv1.VolumeSnapshot, error) {
|
||||
// SnapshotApplication mocks base method.
|
||||
func (m *MockSnapshotRestoreStepper) SnapshotApplication(arg0 context.Context, arg1 *types.CSISnapshotRestoreArgs, arg2 *v10.PersistentVolumeClaim, arg3 string) (*v1.VolumeSnapshot, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SnapshotApplication", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(*snapv1.VolumeSnapshot)
|
||||
ret0, _ := ret[0].(*v1.VolumeSnapshot)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SnapshotApplication indicates an expected call of SnapshotApplication
|
||||
// SnapshotApplication indicates an expected call of SnapshotApplication.
|
||||
func (mr *MockSnapshotRestoreStepperMockRecorder) SnapshotApplication(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SnapshotApplication", reflect.TypeOf((*MockSnapshotRestoreStepper)(nil).SnapshotApplication), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// ValidateArgs mocks base method
|
||||
// ValidateArgs mocks base method.
|
||||
func (m *MockSnapshotRestoreStepper) ValidateArgs(arg0 context.Context, arg1 *types.CSISnapshotRestoreArgs) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ValidateArgs", arg0, arg1)
|
||||
|
@ -103,21 +104,21 @@ func (m *MockSnapshotRestoreStepper) ValidateArgs(arg0 context.Context, arg1 *ty
|
|||
return ret0
|
||||
}
|
||||
|
||||
// ValidateArgs indicates an expected call of ValidateArgs
|
||||
// ValidateArgs indicates an expected call of ValidateArgs.
|
||||
func (mr *MockSnapshotRestoreStepperMockRecorder) ValidateArgs(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateArgs", reflect.TypeOf((*MockSnapshotRestoreStepper)(nil).ValidateArgs), arg0, arg1)
|
||||
}
|
||||
|
||||
// ValidateData mocks base method
|
||||
func (m *MockSnapshotRestoreStepper) ValidateData(arg0 context.Context, arg1 *v1.Pod, arg2 string) error {
|
||||
// ValidateData mocks base method.
|
||||
func (m *MockSnapshotRestoreStepper) ValidateData(arg0 context.Context, arg1 *v10.Pod, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ValidateData", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ValidateData indicates an expected call of ValidateData
|
||||
// ValidateData indicates an expected call of ValidateData.
|
||||
func (mr *MockSnapshotRestoreStepperMockRecorder) ValidateData(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateData", reflect.TypeOf((*MockSnapshotRestoreStepper)(nil).ValidateData), arg0, arg1, arg2)
|
||||
|
|
296
pkg/csi/pvc_inspector.go
Normal file
296
pkg/csi/pvc_inspector.go
Normal file
|
@ -0,0 +1,296 @@
|
|||
package csi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/kastenhq/kubestr/pkg/csi/types"
|
||||
snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
"github.com/pkg/errors"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
sv1 "k8s.io/api/storage/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
type PVCBrowseRunner struct {
|
||||
KubeCli kubernetes.Interface
|
||||
DynCli dynamic.Interface
|
||||
browserSteps PVCBrowserStepper
|
||||
pvc *v1.PersistentVolumeClaim
|
||||
pod *v1.Pod
|
||||
snapshot *snapv1.VolumeSnapshot
|
||||
}
|
||||
|
||||
func (r *PVCBrowseRunner) RunPVCBrowse(ctx context.Context, args *types.PVCBrowseArgs) error {
|
||||
r.browserSteps = &pvcBrowserSteps{
|
||||
validateOps: &validateOperations{
|
||||
kubeCli: r.KubeCli,
|
||||
dynCli: r.DynCli,
|
||||
},
|
||||
versionFetchOps: &apiVersionFetch{
|
||||
kubeCli: r.KubeCli,
|
||||
},
|
||||
createAppOps: &applicationCreate{
|
||||
kubeCli: r.KubeCli,
|
||||
},
|
||||
snapshotCreateOps: &snapshotCreate{
|
||||
kubeCli: r.KubeCli,
|
||||
dynCli: r.DynCli,
|
||||
},
|
||||
portForwardOps: &portforward{},
|
||||
cleanerOps: &cleanse{
|
||||
kubeCli: r.KubeCli,
|
||||
dynCli: r.DynCli,
|
||||
},
|
||||
}
|
||||
return r.RunPVCBrowseHelper(ctx, args)
|
||||
}
|
||||
|
||||
func (r *PVCBrowseRunner) RunPVCBrowseHelper(ctx context.Context, args *types.PVCBrowseArgs) error {
|
||||
defer func() {
|
||||
fmt.Println("Cleaning up resources")
|
||||
r.browserSteps.Cleanup(ctx, r.pvc, r.pod, r.snapshot)
|
||||
}()
|
||||
if r.KubeCli == nil || r.DynCli == nil {
|
||||
return fmt.Errorf("cli uninitialized")
|
||||
}
|
||||
sc, err := r.browserSteps.ValidateArgs(ctx, args)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to validate arguments.")
|
||||
}
|
||||
|
||||
fmt.Println("Taking a snapshot")
|
||||
snapName := snapshotPrefix + time.Now().Format("20060102150405")
|
||||
r.snapshot, err = r.browserSteps.SnapshotPVC(ctx, args, snapName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to snapshot PVC.")
|
||||
}
|
||||
|
||||
fmt.Println("Creating the file browser application.")
|
||||
r.pod, r.pvc, err = r.browserSteps.CreateInspectorApplication(ctx, args, r.snapshot, sc)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to create inspector application.")
|
||||
}
|
||||
|
||||
fmt.Println("Forwarding the port.")
|
||||
err = r.browserSteps.PortForwardAPod(ctx, r.pod, args.LocalPort)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to port forward Pod.")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_pvc_browser_stepper.go -package=mocks . PVCBrowserStepper
|
||||
type PVCBrowserStepper interface {
|
||||
ValidateArgs(ctx context.Context, args *types.PVCBrowseArgs) (*sv1.StorageClass, error)
|
||||
SnapshotPVC(ctx context.Context, args *types.PVCBrowseArgs, snapshotName string) (*snapv1.VolumeSnapshot, error)
|
||||
CreateInspectorApplication(ctx context.Context, args *types.PVCBrowseArgs, snapshot *snapv1.VolumeSnapshot, storageClass *sv1.StorageClass) (*v1.Pod, *v1.PersistentVolumeClaim, error)
|
||||
PortForwardAPod(ctx context.Context, pod *v1.Pod, localPort int) error
|
||||
Cleanup(ctx context.Context, pvc *v1.PersistentVolumeClaim, pod *v1.Pod, snapshot *snapv1.VolumeSnapshot)
|
||||
}
|
||||
|
||||
type pvcBrowserSteps struct {
|
||||
validateOps ArgumentValidator
|
||||
versionFetchOps ApiVersionFetcher
|
||||
createAppOps ApplicationCreator
|
||||
snapshotCreateOps SnapshotCreator
|
||||
portForwardOps PortForwarder
|
||||
cleanerOps Cleaner
|
||||
SnapshotGroupVersion *metav1.GroupVersionForDiscovery
|
||||
}
|
||||
|
||||
func (p *pvcBrowserSteps) ValidateArgs(ctx context.Context, args *types.PVCBrowseArgs) (*sv1.StorageClass, error) {
|
||||
if err := args.Validate(); err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to validate input arguments")
|
||||
}
|
||||
if err := p.validateOps.ValidateNamespace(ctx, args.Namespace); err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to validate Namespace")
|
||||
}
|
||||
pvc, err := p.validateOps.ValidatePVC(ctx, args.PVCName, args.Namespace)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to validate PVC")
|
||||
}
|
||||
|
||||
pvName := pvc.Spec.VolumeName
|
||||
if pvName == "" {
|
||||
return nil, errors.Errorf("PVC (%s) not bound. namespace - (%s)", pvc.Name, pvc.Namespace)
|
||||
}
|
||||
pv, err := p.validateOps.FetchPV(ctx, pvName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to fetch PV")
|
||||
}
|
||||
if pv.Spec.CSI == nil {
|
||||
return nil, errors.New("PVC is not using a CSI volume")
|
||||
}
|
||||
sc, err := p.validateOps.ValidateStorageClass(ctx, *pvc.Spec.StorageClassName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to validate SC")
|
||||
}
|
||||
groupVersion, err := p.versionFetchOps.GetCSISnapshotGroupVersion()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to fetch groupVersion")
|
||||
}
|
||||
p.SnapshotGroupVersion = groupVersion
|
||||
uVSC, err := p.validateOps.ValidateVolumeSnapshotClass(ctx, args.VolumeSnapshotClass, groupVersion)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to validate VolumeSnapshotClass")
|
||||
}
|
||||
vscDriver := getDriverNameFromUVSC(*uVSC, groupVersion.GroupVersion)
|
||||
if sc.Provisioner != vscDriver {
|
||||
return nil, fmt.Errorf("StorageClass provisioner (%s) and VolumeSnapshotClass driver (%s) are different.", sc.Provisioner, vscDriver)
|
||||
}
|
||||
return sc, nil
|
||||
}
|
||||
|
||||
func (p *pvcBrowserSteps) SnapshotPVC(ctx context.Context, args *types.PVCBrowseArgs, snapshotName string) (*snapv1.VolumeSnapshot, error) {
|
||||
snapshotter, err := p.snapshotCreateOps.NewSnapshotter()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to load snapshotter")
|
||||
}
|
||||
createSnapshotArgs := &types.CreateSnapshotArgs{
|
||||
Namespace: args.Namespace,
|
||||
PVCName: args.PVCName,
|
||||
VolumeSnapshotClass: args.VolumeSnapshotClass,
|
||||
SnapshotName: snapshotName,
|
||||
}
|
||||
return p.snapshotCreateOps.CreateSnapshot(ctx, snapshotter, createSnapshotArgs)
|
||||
}
|
||||
|
||||
func (p *pvcBrowserSteps) CreateInspectorApplication(ctx context.Context, args *types.PVCBrowseArgs, snapshot *snapv1.VolumeSnapshot, storageClass *sv1.StorageClass) (*v1.Pod, *v1.PersistentVolumeClaim, error) {
|
||||
snapshotAPIGroup := "snapshot.storage.k8s.io"
|
||||
snapshotKind := "VolumeSnapshot"
|
||||
dataSource := &v1.TypedLocalObjectReference{
|
||||
APIGroup: &snapshotAPIGroup,
|
||||
Kind: snapshotKind,
|
||||
Name: snapshot.Name,
|
||||
}
|
||||
pvcArgs := &types.CreatePVCArgs{
|
||||
GenerateName: clonedPVCGenerateName,
|
||||
StorageClass: storageClass.Name,
|
||||
Namespace: args.Namespace,
|
||||
DataSource: dataSource,
|
||||
RestoreSize: snapshot.Status.RestoreSize,
|
||||
}
|
||||
pvc, err := p.createAppOps.CreatePVC(ctx, pvcArgs)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "Failed to restore PVC")
|
||||
}
|
||||
podArgs := &types.CreatePodArgs{
|
||||
GenerateName: clonedPodGenerateName,
|
||||
PVCName: pvc.Name,
|
||||
Namespace: args.Namespace,
|
||||
RunAsUser: args.RunAsUser,
|
||||
ContainerImage: "filebrowser/filebrowser:v2",
|
||||
ContainerArgs: []string{"--noauth", "-r", "/data"},
|
||||
MountPath: "/data",
|
||||
}
|
||||
pod, err := p.createAppOps.CreatePod(ctx, podArgs)
|
||||
if err != nil {
|
||||
return nil, pvc, errors.Wrap(err, "Failed to create restored Pod")
|
||||
}
|
||||
if err = p.createAppOps.WaitForPodReady(ctx, args.Namespace, pod.Name); err != nil {
|
||||
return pod, pvc, errors.Wrap(err, "Pod failed to become ready")
|
||||
}
|
||||
return pod, pvc, nil
|
||||
}
|
||||
|
||||
func (p *pvcBrowserSteps) PortForwardAPod(ctx context.Context, pod *v1.Pod, localPort int) error {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
stopChan, readyChan, errChan := make(chan struct{}, 1), make(chan struct{}, 1), make(chan string)
|
||||
out, errOut := new(bytes.Buffer), new(bytes.Buffer)
|
||||
cfg, err := p.portForwardOps.FetchRestConfig()
|
||||
if err != nil {
|
||||
return errors.New("Failed to fetch rest config")
|
||||
}
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-sigs
|
||||
fmt.Println("Stopping port forward")
|
||||
close(stopChan)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
pfArgs := &types.PortForwardAPodRequest{
|
||||
RestConfig: cfg,
|
||||
Pod: pod,
|
||||
LocalPort: localPort,
|
||||
PodPort: 80,
|
||||
OutStream: bytes.Buffer(*out),
|
||||
ErrOutStream: bytes.Buffer(*errOut),
|
||||
StopCh: stopChan,
|
||||
ReadyCh: readyChan,
|
||||
}
|
||||
err = p.portForwardOps.PortForwardAPod(pfArgs)
|
||||
if err != nil {
|
||||
errChan <- fmt.Sprintf("Failed to port forward (%s)", err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-readyChan:
|
||||
url := fmt.Sprintf("http://localhost:%d/", localPort)
|
||||
fmt.Printf("Port forwarding is ready to get traffic. visit %s\n", url)
|
||||
openbrowser(url)
|
||||
wg.Wait()
|
||||
case msg := <-errChan:
|
||||
return errors.New(msg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pvcBrowserSteps) Cleanup(ctx context.Context, pvc *v1.PersistentVolumeClaim, pod *v1.Pod, snapshot *snapv1.VolumeSnapshot) {
|
||||
if pvc != nil {
|
||||
err := p.cleanerOps.DeletePVC(ctx, pvc.Name, pvc.Namespace)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to delete PVC", pvc)
|
||||
}
|
||||
}
|
||||
if pod != nil {
|
||||
err := p.cleanerOps.DeletePod(ctx, pod.Name, pod.Namespace)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to delete Pod", pod)
|
||||
}
|
||||
}
|
||||
if snapshot != nil {
|
||||
err := p.cleanerOps.DeleteSnapshot(ctx, snapshot.Name, snapshot.Namespace, p.SnapshotGroupVersion)
|
||||
if err != nil {
|
||||
fmt.Println("Failed to delete Snapshot", snapshot)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func openbrowser(url string) {
|
||||
var err error
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
err = exec.Command("xdg-open", url).Start()
|
||||
case "windows":
|
||||
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
|
||||
case "darwin":
|
||||
err = exec.Command("open", url).Start()
|
||||
default:
|
||||
err = fmt.Errorf("unsupported platform")
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
777
pkg/csi/pvc_inspector_steps_test.go
Normal file
777
pkg/csi/pvc_inspector_steps_test.go
Normal file
|
@ -0,0 +1,777 @@
|
|||
package csi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/kastenhq/kubestr/pkg/common"
|
||||
"github.com/kastenhq/kubestr/pkg/csi/mocks"
|
||||
"github.com/kastenhq/kubestr/pkg/csi/types"
|
||||
snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
. "gopkg.in/check.v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
sv1 "k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func (s *CSITestSuite) TestPvcBrowseValidateArgs(c *C) {
|
||||
ctx := context.Background()
|
||||
scName := "sc"
|
||||
type fields struct {
|
||||
validateOps *mocks.MockArgumentValidator
|
||||
versionOps *mocks.MockApiVersionFetcher
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
args *types.PVCBrowseArgs
|
||||
prepare func(f *fields)
|
||||
errChecker Checker
|
||||
}{
|
||||
{ // valid args
|
||||
args: &types.PVCBrowseArgs{
|
||||
PVCName: "pvc",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||
f.validateOps.EXPECT().ValidatePVC(gomock.Any(), "pvc", "ns").Return(
|
||||
&v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
VolumeName: "vol",
|
||||
StorageClassName: &scName,
|
||||
},
|
||||
}, nil,
|
||||
),
|
||||
f.validateOps.EXPECT().FetchPV(gomock.Any(), "vol").Return(
|
||||
&v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "vol",
|
||||
},
|
||||
Spec: v1.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||
CSI: &v1.CSIPersistentVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
),
|
||||
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), "sc").Return(
|
||||
&sv1.StorageClass{
|
||||
Provisioner: "p1",
|
||||
}, nil),
|
||||
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(
|
||||
&metav1.GroupVersionForDiscovery{
|
||||
GroupVersion: common.SnapshotAlphaVersion,
|
||||
}, nil),
|
||||
f.validateOps.EXPECT().ValidateVolumeSnapshotClass(gomock.Any(), "vsc", &metav1.GroupVersionForDiscovery{
|
||||
GroupVersion: common.SnapshotAlphaVersion,
|
||||
}).Return(&unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
common.VolSnapClassAlphaDriverKey: "p1",
|
||||
},
|
||||
}, nil),
|
||||
)
|
||||
},
|
||||
errChecker: IsNil,
|
||||
},
|
||||
{ // driver mismatch
|
||||
args: &types.PVCBrowseArgs{
|
||||
PVCName: "pvc",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||
f.validateOps.EXPECT().ValidatePVC(gomock.Any(), "pvc", "ns").Return(
|
||||
&v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
VolumeName: "vol",
|
||||
StorageClassName: &scName,
|
||||
},
|
||||
}, nil,
|
||||
),
|
||||
f.validateOps.EXPECT().FetchPV(gomock.Any(), "vol").Return(
|
||||
&v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "vol",
|
||||
},
|
||||
Spec: v1.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||
CSI: &v1.CSIPersistentVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
),
|
||||
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), gomock.Any()).Return(
|
||||
&sv1.StorageClass{
|
||||
Provisioner: "p1",
|
||||
}, nil),
|
||||
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(
|
||||
&metav1.GroupVersionForDiscovery{
|
||||
GroupVersion: common.SnapshotAlphaVersion,
|
||||
}, nil),
|
||||
f.validateOps.EXPECT().ValidateVolumeSnapshotClass(gomock.Any(), "vsc", &metav1.GroupVersionForDiscovery{
|
||||
GroupVersion: common.SnapshotAlphaVersion,
|
||||
}).Return(&unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
common.VolSnapClassAlphaDriverKey: "p2",
|
||||
},
|
||||
}, nil),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{ // vsc error
|
||||
args: &types.PVCBrowseArgs{
|
||||
PVCName: "pvc",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||
f.validateOps.EXPECT().ValidatePVC(gomock.Any(), gomock.Any(), gomock.Any()).Return(
|
||||
&v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
VolumeName: "vol",
|
||||
StorageClassName: &scName,
|
||||
},
|
||||
}, nil,
|
||||
),
|
||||
f.validateOps.EXPECT().FetchPV(gomock.Any(), "vol").Return(
|
||||
&v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "vol",
|
||||
},
|
||||
Spec: v1.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||
CSI: &v1.CSIPersistentVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
),
|
||||
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), gomock.Any()).Return(nil, nil),
|
||||
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(nil, nil),
|
||||
f.validateOps.EXPECT().ValidateVolumeSnapshotClass(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("vsc error")),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{ // get driver versionn error
|
||||
args: &types.PVCBrowseArgs{
|
||||
PVCName: "pvc",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||
f.validateOps.EXPECT().ValidatePVC(gomock.Any(), gomock.Any(), gomock.Any()).Return(
|
||||
&v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
VolumeName: "vol",
|
||||
StorageClassName: &scName,
|
||||
},
|
||||
}, nil,
|
||||
),
|
||||
f.validateOps.EXPECT().FetchPV(gomock.Any(), "vol").Return(
|
||||
&v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "vol",
|
||||
},
|
||||
Spec: v1.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||
CSI: &v1.CSIPersistentVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
),
|
||||
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), gomock.Any()).Return(nil, nil),
|
||||
f.versionOps.EXPECT().GetCSISnapshotGroupVersion().Return(nil, fmt.Errorf("driver version error")),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{ // sc error
|
||||
args: &types.PVCBrowseArgs{
|
||||
PVCName: "pvc",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||
f.validateOps.EXPECT().ValidatePVC(gomock.Any(), gomock.Any(), gomock.Any()).Return(
|
||||
&v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
VolumeName: "vol",
|
||||
StorageClassName: &scName,
|
||||
},
|
||||
}, nil,
|
||||
),
|
||||
f.validateOps.EXPECT().FetchPV(gomock.Any(), "vol").Return(
|
||||
&v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "vol",
|
||||
},
|
||||
Spec: v1.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||
CSI: &v1.CSIPersistentVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
),
|
||||
f.validateOps.EXPECT().ValidateStorageClass(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("sc error")),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{ // non csi error
|
||||
args: &types.PVCBrowseArgs{
|
||||
PVCName: "pvc",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||
f.validateOps.EXPECT().ValidatePVC(gomock.Any(), gomock.Any(), gomock.Any()).Return(
|
||||
&v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
VolumeName: "vol",
|
||||
StorageClassName: &scName,
|
||||
},
|
||||
}, nil,
|
||||
),
|
||||
f.validateOps.EXPECT().FetchPV(gomock.Any(), "vol").Return(
|
||||
&v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "vol",
|
||||
},
|
||||
Spec: v1.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{ // fetch pv error
|
||||
args: &types.PVCBrowseArgs{
|
||||
PVCName: "pvc",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||
f.validateOps.EXPECT().ValidatePVC(gomock.Any(), gomock.Any(), gomock.Any()).Return(
|
||||
&v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
VolumeName: "vol",
|
||||
StorageClassName: &scName,
|
||||
},
|
||||
}, nil,
|
||||
),
|
||||
f.validateOps.EXPECT().FetchPV(gomock.Any(), "vol").Return(nil, fmt.Errorf("pv fail")),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{ // validate pvc error
|
||||
args: &types.PVCBrowseArgs{
|
||||
PVCName: "pvc",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(nil),
|
||||
f.validateOps.EXPECT().ValidatePVC(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("validate pvc error")),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{ // validate ns error
|
||||
args: &types.PVCBrowseArgs{
|
||||
PVCName: "pvc",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.validateOps.EXPECT().ValidateNamespace(gomock.Any(), "ns").Return(fmt.Errorf("validate ns error")),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{ // validate pvc error
|
||||
args: &types.PVCBrowseArgs{
|
||||
PVCName: "",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{ // validate vsc error
|
||||
args: &types.PVCBrowseArgs{
|
||||
PVCName: "dfd",
|
||||
VolumeSnapshotClass: "",
|
||||
Namespace: "ns",
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{ // validate ns error
|
||||
args: &types.PVCBrowseArgs{
|
||||
PVCName: "dfd",
|
||||
VolumeSnapshotClass: "ddd",
|
||||
Namespace: "",
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
} {
|
||||
ctrl := gomock.NewController(c)
|
||||
defer ctrl.Finish()
|
||||
f := fields{
|
||||
validateOps: mocks.NewMockArgumentValidator(ctrl),
|
||||
versionOps: mocks.NewMockApiVersionFetcher(ctrl),
|
||||
}
|
||||
if tc.prepare != nil {
|
||||
tc.prepare(&f)
|
||||
}
|
||||
stepper := &pvcBrowserSteps{
|
||||
validateOps: f.validateOps,
|
||||
versionFetchOps: f.versionOps,
|
||||
}
|
||||
_, err := stepper.ValidateArgs(ctx, tc.args)
|
||||
c.Check(err, tc.errChecker)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CSITestSuite) TestPvcBrowseSnapshotPVC(c *C) {
|
||||
ctx := context.Background()
|
||||
snapshotter := &fakeSnapshotter{name: "snapshotter"}
|
||||
groupversion := &metav1.GroupVersionForDiscovery{
|
||||
GroupVersion: "gv",
|
||||
Version: "v",
|
||||
}
|
||||
type fields struct {
|
||||
snapshotOps *mocks.MockSnapshotCreator
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
args *types.PVCBrowseArgs
|
||||
snapshotName string
|
||||
prepare func(f *fields)
|
||||
errChecker Checker
|
||||
snapChecker Checker
|
||||
}{
|
||||
{
|
||||
args: &types.PVCBrowseArgs{
|
||||
Namespace: "ns",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
PVCName: "pvc1",
|
||||
},
|
||||
snapshotName: "snap1",
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.snapshotOps.EXPECT().NewSnapshotter().Return(snapshotter, nil),
|
||||
f.snapshotOps.EXPECT().CreateSnapshot(gomock.Any(), snapshotter, &types.CreateSnapshotArgs{
|
||||
Namespace: "ns",
|
||||
PVCName: "pvc1",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
SnapshotName: "snap1",
|
||||
}).Return(&snapv1.VolumeSnapshot{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "createdName",
|
||||
},
|
||||
}, nil),
|
||||
)
|
||||
},
|
||||
errChecker: IsNil,
|
||||
snapChecker: NotNil,
|
||||
},
|
||||
{
|
||||
args: &types.PVCBrowseArgs{
|
||||
Namespace: "ns",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
PVCName: "pvc1",
|
||||
},
|
||||
snapshotName: "snap1",
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.snapshotOps.EXPECT().NewSnapshotter().Return(snapshotter, nil),
|
||||
f.snapshotOps.EXPECT().CreateSnapshot(gomock.Any(), snapshotter, &types.CreateSnapshotArgs{
|
||||
Namespace: "ns",
|
||||
PVCName: "pvc1",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
SnapshotName: "snap1",
|
||||
}).Return(nil, fmt.Errorf("error")),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
snapChecker: IsNil,
|
||||
},
|
||||
{
|
||||
args: &types.PVCBrowseArgs{
|
||||
Namespace: "ns",
|
||||
VolumeSnapshotClass: "vsc",
|
||||
PVCName: "pvc1",
|
||||
},
|
||||
snapshotName: "snap1",
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.snapshotOps.EXPECT().NewSnapshotter().Return(nil, fmt.Errorf("error")),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
snapChecker: IsNil,
|
||||
},
|
||||
} {
|
||||
ctrl := gomock.NewController(c)
|
||||
defer ctrl.Finish()
|
||||
f := fields{
|
||||
snapshotOps: mocks.NewMockSnapshotCreator(ctrl),
|
||||
}
|
||||
if tc.prepare != nil {
|
||||
tc.prepare(&f)
|
||||
}
|
||||
stepper := &pvcBrowserSteps{
|
||||
snapshotCreateOps: f.snapshotOps,
|
||||
SnapshotGroupVersion: groupversion,
|
||||
}
|
||||
snapshot, err := stepper.SnapshotPVC(ctx, tc.args, tc.snapshotName)
|
||||
c.Check(err, tc.errChecker)
|
||||
c.Check(snapshot, tc.snapChecker)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CSITestSuite) TestCreateInspectorApplication(c *C) {
|
||||
ctx := context.Background()
|
||||
resourceQuantity := resource.MustParse("1Gi")
|
||||
snapshotAPIGroup := "snapshot.storage.k8s.io"
|
||||
type fields struct {
|
||||
createAppOps *mocks.MockApplicationCreator
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
args *types.PVCBrowseArgs
|
||||
snapshot *snapv1.VolumeSnapshot
|
||||
sc *sv1.StorageClass
|
||||
prepare func(f *fields)
|
||||
errChecker Checker
|
||||
podChecker Checker
|
||||
pvcChecker Checker
|
||||
}{
|
||||
{
|
||||
args: &types.PVCBrowseArgs{
|
||||
Namespace: "ns",
|
||||
RunAsUser: 100,
|
||||
},
|
||||
sc: &sv1.StorageClass{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "sc",
|
||||
},
|
||||
},
|
||||
snapshot: &snapv1.VolumeSnapshot{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "snap1",
|
||||
},
|
||||
Status: &snapv1.VolumeSnapshotStatus{
|
||||
RestoreSize: &resourceQuantity,
|
||||
},
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), &types.CreatePVCArgs{
|
||||
GenerateName: clonedPVCGenerateName,
|
||||
StorageClass: "sc",
|
||||
Namespace: "ns",
|
||||
DataSource: &v1.TypedLocalObjectReference{
|
||||
APIGroup: &snapshotAPIGroup,
|
||||
Kind: "VolumeSnapshot",
|
||||
Name: "snap1",
|
||||
},
|
||||
RestoreSize: &resourceQuantity,
|
||||
}).Return(&v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc1",
|
||||
},
|
||||
}, nil),
|
||||
f.createAppOps.EXPECT().CreatePod(gomock.Any(), &types.CreatePodArgs{
|
||||
GenerateName: clonedPodGenerateName,
|
||||
PVCName: "pvc1",
|
||||
Namespace: "ns",
|
||||
ContainerArgs: []string{"--noauth", "-r", "/data"},
|
||||
MountPath: "/data",
|
||||
RunAsUser: 100,
|
||||
ContainerImage: "filebrowser/filebrowser:v2",
|
||||
}).Return(&v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod1",
|
||||
},
|
||||
}, nil),
|
||||
f.createAppOps.EXPECT().WaitForPodReady(gomock.Any(), "ns", "pod1").Return(nil),
|
||||
)
|
||||
},
|
||||
errChecker: IsNil,
|
||||
podChecker: NotNil,
|
||||
pvcChecker: NotNil,
|
||||
},
|
||||
{
|
||||
args: &types.PVCBrowseArgs{
|
||||
Namespace: "ns",
|
||||
RunAsUser: 100,
|
||||
},
|
||||
sc: &sv1.StorageClass{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "sc",
|
||||
},
|
||||
},
|
||||
snapshot: &snapv1.VolumeSnapshot{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "snap1",
|
||||
},
|
||||
Status: &snapv1.VolumeSnapshotStatus{
|
||||
RestoreSize: &resourceQuantity,
|
||||
},
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), &types.CreatePVCArgs{
|
||||
GenerateName: clonedPVCGenerateName,
|
||||
StorageClass: "sc",
|
||||
Namespace: "ns",
|
||||
DataSource: &v1.TypedLocalObjectReference{
|
||||
APIGroup: &snapshotAPIGroup,
|
||||
Kind: "VolumeSnapshot",
|
||||
Name: "snap1",
|
||||
},
|
||||
RestoreSize: &resourceQuantity,
|
||||
}).Return(&v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc1",
|
||||
},
|
||||
}, nil),
|
||||
f.createAppOps.EXPECT().CreatePod(gomock.Any(), &types.CreatePodArgs{
|
||||
GenerateName: clonedPodGenerateName,
|
||||
PVCName: "pvc1",
|
||||
Namespace: "ns",
|
||||
ContainerArgs: []string{"--noauth", "-r", "/data"},
|
||||
MountPath: "/data",
|
||||
RunAsUser: 100,
|
||||
ContainerImage: "filebrowser/filebrowser:v2",
|
||||
}).Return(&v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod1",
|
||||
},
|
||||
}, nil),
|
||||
f.createAppOps.EXPECT().WaitForPodReady(gomock.Any(), "ns", "pod1").Return(fmt.Errorf("pod ready error")),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
podChecker: NotNil,
|
||||
pvcChecker: NotNil,
|
||||
},
|
||||
{
|
||||
args: &types.PVCBrowseArgs{
|
||||
Namespace: "ns",
|
||||
RunAsUser: 100,
|
||||
},
|
||||
sc: &sv1.StorageClass{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "sc",
|
||||
},
|
||||
},
|
||||
snapshot: &snapv1.VolumeSnapshot{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "snap1",
|
||||
},
|
||||
Status: &snapv1.VolumeSnapshotStatus{
|
||||
RestoreSize: &resourceQuantity,
|
||||
},
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), gomock.Any()).Return(&v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc1",
|
||||
},
|
||||
}, nil),
|
||||
f.createAppOps.EXPECT().CreatePod(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("pod error")),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
podChecker: IsNil,
|
||||
pvcChecker: NotNil,
|
||||
},
|
||||
{
|
||||
args: &types.PVCBrowseArgs{
|
||||
Namespace: "ns",
|
||||
RunAsUser: 100,
|
||||
},
|
||||
sc: &sv1.StorageClass{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "sc",
|
||||
},
|
||||
},
|
||||
snapshot: &snapv1.VolumeSnapshot{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "snap1",
|
||||
},
|
||||
Status: &snapv1.VolumeSnapshotStatus{
|
||||
RestoreSize: &resourceQuantity,
|
||||
},
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.createAppOps.EXPECT().CreatePVC(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("error")),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
podChecker: IsNil,
|
||||
pvcChecker: IsNil,
|
||||
},
|
||||
} {
|
||||
ctrl := gomock.NewController(c)
|
||||
defer ctrl.Finish()
|
||||
f := fields{
|
||||
createAppOps: mocks.NewMockApplicationCreator(ctrl),
|
||||
}
|
||||
if tc.prepare != nil {
|
||||
tc.prepare(&f)
|
||||
}
|
||||
stepper := &pvcBrowserSteps{
|
||||
createAppOps: f.createAppOps,
|
||||
}
|
||||
pod, pvc, err := stepper.CreateInspectorApplication(ctx, tc.args, tc.snapshot, tc.sc)
|
||||
c.Check(err, tc.errChecker)
|
||||
c.Check(pod, tc.podChecker)
|
||||
c.Check(pvc, tc.pvcChecker)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CSITestSuite) TestPVCBrowseCleanup(c *C) {
|
||||
ctx := context.Background()
|
||||
groupversion := &metav1.GroupVersionForDiscovery{
|
||||
GroupVersion: "gv",
|
||||
Version: "v",
|
||||
}
|
||||
type fields struct {
|
||||
cleanerOps *mocks.MockCleaner
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
pvc *v1.PersistentVolumeClaim
|
||||
pod *v1.Pod
|
||||
snapshot *snapv1.VolumeSnapshot
|
||||
prepare func(f *fields)
|
||||
}{
|
||||
{
|
||||
pvc: &v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
},
|
||||
pod: &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod",
|
||||
Namespace: "ns",
|
||||
},
|
||||
},
|
||||
snapshot: &snapv1.VolumeSnapshot{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "snap1",
|
||||
Namespace: "ns",
|
||||
},
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.cleanerOps.EXPECT().DeletePVC(ctx, "pvc", "ns").Return(nil),
|
||||
f.cleanerOps.EXPECT().DeletePod(ctx, "pod", "ns").Return(nil),
|
||||
f.cleanerOps.EXPECT().DeleteSnapshot(ctx, "snap1", "ns", groupversion).Return(nil),
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
pvc: &v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc",
|
||||
Namespace: "ns",
|
||||
},
|
||||
},
|
||||
pod: &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod",
|
||||
Namespace: "ns",
|
||||
},
|
||||
},
|
||||
snapshot: &snapv1.VolumeSnapshot{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "snap1",
|
||||
Namespace: "ns",
|
||||
},
|
||||
},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.cleanerOps.EXPECT().DeletePVC(ctx, "pvc", "ns").Return(fmt.Errorf("err")),
|
||||
f.cleanerOps.EXPECT().DeletePod(ctx, "pod", "ns").Return(fmt.Errorf("err")),
|
||||
f.cleanerOps.EXPECT().DeleteSnapshot(ctx, "snap1", "ns", groupversion).Return(fmt.Errorf("err")),
|
||||
)
|
||||
},
|
||||
},
|
||||
} {
|
||||
ctrl := gomock.NewController(c)
|
||||
defer ctrl.Finish()
|
||||
f := fields{
|
||||
cleanerOps: mocks.NewMockCleaner(ctrl),
|
||||
}
|
||||
if tc.prepare != nil {
|
||||
tc.prepare(&f)
|
||||
}
|
||||
stepper := &pvcBrowserSteps{
|
||||
cleanerOps: f.cleanerOps,
|
||||
SnapshotGroupVersion: groupversion,
|
||||
}
|
||||
stepper.Cleanup(ctx, tc.pvc, tc.pod, tc.snapshot)
|
||||
}
|
||||
}
|
213
pkg/csi/pvc_inspector_test.go
Normal file
213
pkg/csi/pvc_inspector_test.go
Normal file
|
@ -0,0 +1,213 @@
|
|||
package csi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/kastenhq/kubestr/pkg/csi/mocks"
|
||||
"github.com/kastenhq/kubestr/pkg/csi/types"
|
||||
snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
. "gopkg.in/check.v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
sv1 "k8s.io/api/storage/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/dynamic"
|
||||
fakedynamic "k8s.io/client-go/dynamic/fake"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
func (s *CSITestSuite) TestRunPVCBrowseHelper(c *C) {
|
||||
ctx := context.Background()
|
||||
type fields struct {
|
||||
stepperOps *mocks.MockPVCBrowserStepper
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
kubeCli kubernetes.Interface
|
||||
dynCli dynamic.Interface
|
||||
args *types.PVCBrowseArgs
|
||||
prepare func(f *fields)
|
||||
errChecker Checker
|
||||
}{
|
||||
{
|
||||
// success
|
||||
kubeCli: fake.NewSimpleClientset(),
|
||||
dynCli: fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()),
|
||||
args: &types.PVCBrowseArgs{},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.stepperOps.EXPECT().ValidateArgs(gomock.Any(), gomock.Any()).Return(
|
||||
&sv1.StorageClass{}, nil,
|
||||
),
|
||||
f.stepperOps.EXPECT().SnapshotPVC(gomock.Any(), gomock.Any(), gomock.Any()).Return(
|
||||
&snapv1.VolumeSnapshot{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "snap1",
|
||||
Namespace: "ns",
|
||||
}}, nil,
|
||||
),
|
||||
f.stepperOps.EXPECT().CreateInspectorApplication(gomock.Any(), gomock.Any(),
|
||||
&snapv1.VolumeSnapshot{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "snap1",
|
||||
Namespace: "ns",
|
||||
},
|
||||
}, &sv1.StorageClass{},
|
||||
).Return(
|
||||
&v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod1",
|
||||
Namespace: "ns",
|
||||
},
|
||||
},
|
||||
&v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc1",
|
||||
Namespace: "ns",
|
||||
},
|
||||
},
|
||||
nil,
|
||||
),
|
||||
f.stepperOps.EXPECT().PortForwardAPod(gomock.Any(),
|
||||
&v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod1",
|
||||
Namespace: "ns",
|
||||
},
|
||||
}, gomock.Any(),
|
||||
).Return(nil),
|
||||
f.stepperOps.EXPECT().Cleanup(gomock.Any(),
|
||||
&v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pvc1",
|
||||
Namespace: "ns",
|
||||
},
|
||||
},
|
||||
&v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod1",
|
||||
Namespace: "ns",
|
||||
},
|
||||
},
|
||||
&snapv1.VolumeSnapshot{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "snap1",
|
||||
Namespace: "ns",
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
},
|
||||
errChecker: IsNil,
|
||||
},
|
||||
{
|
||||
// portforward failure
|
||||
kubeCli: fake.NewSimpleClientset(),
|
||||
dynCli: fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()),
|
||||
args: &types.PVCBrowseArgs{},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.stepperOps.EXPECT().ValidateArgs(gomock.Any(), gomock.Any()).Return(nil, nil),
|
||||
f.stepperOps.EXPECT().SnapshotPVC(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil),
|
||||
f.stepperOps.EXPECT().CreateInspectorApplication(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil, nil),
|
||||
f.stepperOps.EXPECT().PortForwardAPod(gomock.Any(), gomock.Any(), gomock.Any()).Return(fmt.Errorf("portforward error")),
|
||||
f.stepperOps.EXPECT().Cleanup(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{
|
||||
// createapp failure
|
||||
kubeCli: fake.NewSimpleClientset(),
|
||||
dynCli: fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()),
|
||||
args: &types.PVCBrowseArgs{},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.stepperOps.EXPECT().ValidateArgs(gomock.Any(), gomock.Any()).Return(nil, nil),
|
||||
f.stepperOps.EXPECT().SnapshotPVC(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil),
|
||||
f.stepperOps.EXPECT().CreateInspectorApplication(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil, fmt.Errorf("createapp error")),
|
||||
f.stepperOps.EXPECT().Cleanup(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{
|
||||
// snapshot failure
|
||||
kubeCli: fake.NewSimpleClientset(),
|
||||
dynCli: fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()),
|
||||
args: &types.PVCBrowseArgs{},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.stepperOps.EXPECT().ValidateArgs(gomock.Any(), gomock.Any()).Return(nil, nil),
|
||||
f.stepperOps.EXPECT().SnapshotPVC(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("snapshot error")),
|
||||
f.stepperOps.EXPECT().Cleanup(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{
|
||||
// validate failure
|
||||
kubeCli: fake.NewSimpleClientset(),
|
||||
dynCli: fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()),
|
||||
args: &types.PVCBrowseArgs{},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.stepperOps.EXPECT().ValidateArgs(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("snapshot error")),
|
||||
f.stepperOps.EXPECT().Cleanup(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{
|
||||
// emptycli failure
|
||||
kubeCli: nil,
|
||||
dynCli: fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()),
|
||||
args: &types.PVCBrowseArgs{},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.stepperOps.EXPECT().Cleanup(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
{
|
||||
// emptydyncli failure
|
||||
kubeCli: fake.NewSimpleClientset(),
|
||||
dynCli: nil,
|
||||
args: &types.PVCBrowseArgs{},
|
||||
prepare: func(f *fields) {
|
||||
gomock.InOrder(
|
||||
f.stepperOps.EXPECT().Cleanup(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()),
|
||||
)
|
||||
},
|
||||
errChecker: NotNil,
|
||||
},
|
||||
} {
|
||||
ctrl := gomock.NewController(c)
|
||||
defer ctrl.Finish()
|
||||
f := fields{
|
||||
stepperOps: mocks.NewMockPVCBrowserStepper(ctrl),
|
||||
}
|
||||
if tc.prepare != nil {
|
||||
tc.prepare(&f)
|
||||
}
|
||||
runner := &PVCBrowseRunner{
|
||||
KubeCli: tc.kubeCli,
|
||||
DynCli: tc.dynCli,
|
||||
browserSteps: f.stepperOps,
|
||||
}
|
||||
err := runner.RunPVCBrowseHelper(ctx, tc.args)
|
||||
c.Check(err, tc.errChecker)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CSITestSuite) TestPVCBrowseRunner(c *C) {
|
||||
ctx := context.Background()
|
||||
r := &PVCBrowseRunner{
|
||||
browserSteps: &pvcBrowserSteps{},
|
||||
}
|
||||
err := r.RunPVCBrowseHelper(ctx, nil)
|
||||
c.Check(err, NotNil)
|
||||
}
|
|
@ -5,18 +5,13 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
kankube "github.com/kanisterio/kanister/pkg/kube"
|
||||
kansnapshot "github.com/kanisterio/kanister/pkg/kube/snapshot"
|
||||
"github.com/kastenhq/kubestr/pkg/common"
|
||||
"github.com/kastenhq/kubestr/pkg/csi/types"
|
||||
snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
"github.com/pkg/errors"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
sv1 "k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
@ -114,7 +109,7 @@ func (r *SnapshotRestoreRunner) RunSnapshotRestoreHelper(ctx context.Context, ar
|
|||
return results, err
|
||||
}
|
||||
|
||||
//go:generate mockgen -destination=mocks/mock_snapshot_restore_stepper.go -package=mocks . SnapshotRestoreStepper
|
||||
//go:generate go run github.com/golang/mock/mockgen -destination=mocks/mock_snapshot_restore_stepper.go -package=mocks . SnapshotRestoreStepper
|
||||
type SnapshotRestoreStepper interface {
|
||||
ValidateArgs(ctx context.Context, args *types.CSISnapshotRestoreArgs) error
|
||||
CreateApplication(ctx context.Context, args *types.CSISnapshotRestoreArgs, data string) (*v1.Pod, *v1.PersistentVolumeClaim, error)
|
||||
|
@ -178,9 +173,11 @@ func (s *snapshotRestoreSteps) CreateApplication(ctx context.Context, args *type
|
|||
GenerateName: originalPodGenerateName,
|
||||
PVCName: pvc.Name,
|
||||
Namespace: args.Namespace,
|
||||
Cmd: fmt.Sprintf("echo '%s' >> /data/out.txt; sync; tail -f /dev/null", genString),
|
||||
RunAsUser: args.RunAsUser,
|
||||
ContainerImage: args.ContainerImage,
|
||||
Command: []string{"/bin/sh"},
|
||||
ContainerArgs: []string{"-c", fmt.Sprintf("echo '%s' >> /data/out.txt; sync; tail -f /dev/null", genString)},
|
||||
MountPath: "/data",
|
||||
}
|
||||
pod, err := s.createAppOps.CreatePod(ctx, podArgs)
|
||||
if err != nil {
|
||||
|
@ -254,9 +251,11 @@ func (s *snapshotRestoreSteps) RestoreApplication(ctx context.Context, args *typ
|
|||
GenerateName: clonedPodGenerateName,
|
||||
PVCName: pvc.Name,
|
||||
Namespace: args.Namespace,
|
||||
Cmd: "tail -f /dev/null",
|
||||
RunAsUser: args.RunAsUser,
|
||||
ContainerImage: args.ContainerImage,
|
||||
Command: []string{"/bin/sh"},
|
||||
ContainerArgs: []string{"-c", "tail -f /dev/null"},
|
||||
MountPath: "/data",
|
||||
}
|
||||
pod, err := s.createAppOps.CreatePod(ctx, podArgs)
|
||||
if err != nil {
|
||||
|
@ -304,323 +303,6 @@ func (s *snapshotRestoreSteps) Cleanup(ctx context.Context, results *types.CSISn
|
|||
}
|
||||
}
|
||||
|
||||
//go:generate mockgen -destination=mocks/mock_argument_validator.go -package=mocks . ArgumentValidator
|
||||
type ArgumentValidator interface {
|
||||
ValidateNamespace(ctx context.Context, namespace string) error
|
||||
ValidateStorageClass(ctx context.Context, storageClass string) (*sv1.StorageClass, error)
|
||||
ValidateVolumeSnapshotClass(ctx context.Context, volumeSnapshotClass string, groupVersion *metav1.GroupVersionForDiscovery) (*unstructured.Unstructured, error)
|
||||
}
|
||||
|
||||
type validateOperations struct {
|
||||
kubeCli kubernetes.Interface
|
||||
dynCli dynamic.Interface
|
||||
}
|
||||
|
||||
func (o *validateOperations) ValidateNamespace(ctx context.Context, namespace string) error {
|
||||
if o.kubeCli == nil {
|
||||
return fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
_, err := o.kubeCli.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *validateOperations) ValidateStorageClass(ctx context.Context, storageClass string) (*sv1.StorageClass, error) {
|
||||
if o.kubeCli == nil {
|
||||
return nil, fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
return o.kubeCli.StorageV1().StorageClasses().Get(ctx, storageClass, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func (o *validateOperations) ValidateVolumeSnapshotClass(ctx context.Context, volumeSnapshotClass string, groupVersion *metav1.GroupVersionForDiscovery) (*unstructured.Unstructured, error) {
|
||||
if o.dynCli == nil {
|
||||
return nil, fmt.Errorf("dynCli not initialized")
|
||||
}
|
||||
VolSnapClassGVR := schema.GroupVersionResource{Group: common.SnapGroupName, Version: groupVersion.Version, Resource: common.VolumeSnapshotClassResourcePlural}
|
||||
return o.dynCli.Resource(VolSnapClassGVR).Get(ctx, volumeSnapshotClass, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
//go:generate mockgen -destination=mocks/mock_application_creator.go -package=mocks . ApplicationCreator
|
||||
type ApplicationCreator interface {
|
||||
CreatePVC(ctx context.Context, args *types.CreatePVCArgs) (*v1.PersistentVolumeClaim, error)
|
||||
CreatePod(ctx context.Context, args *types.CreatePodArgs) (*v1.Pod, error)
|
||||
WaitForPodReady(ctx context.Context, namespace string, podName string) error
|
||||
}
|
||||
|
||||
type applicationCreate struct {
|
||||
kubeCli kubernetes.Interface
|
||||
}
|
||||
|
||||
func (c *applicationCreate) CreatePVC(ctx context.Context, args *types.CreatePVCArgs) (*v1.PersistentVolumeClaim, error) {
|
||||
if c.kubeCli == nil {
|
||||
return nil, fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
if err := args.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pvc := &v1.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: args.GenerateName,
|
||||
Namespace: args.Namespace,
|
||||
Labels: map[string]string{
|
||||
createdByLabel: "yes",
|
||||
},
|
||||
},
|
||||
Spec: v1.PersistentVolumeClaimSpec{
|
||||
AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce},
|
||||
StorageClassName: &args.StorageClass,
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceStorage: resource.MustParse("1Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if args.DataSource != nil {
|
||||
pvc.Spec.DataSource = args.DataSource
|
||||
}
|
||||
|
||||
if args.RestoreSize != nil && !args.RestoreSize.IsZero() {
|
||||
pvc.Spec.Resources.Requests[v1.ResourceStorage] = *args.RestoreSize
|
||||
}
|
||||
|
||||
pvcRes, err := c.kubeCli.CoreV1().PersistentVolumeClaims(args.Namespace).Create(ctx, pvc, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return pvc, err
|
||||
}
|
||||
|
||||
return pvcRes, nil
|
||||
}
|
||||
|
||||
func (c *applicationCreate) CreatePod(ctx context.Context, args *types.CreatePodArgs) (*v1.Pod, error) {
|
||||
if c.kubeCli == nil {
|
||||
return nil, fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
if err := args.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.ContainerImage == "" {
|
||||
args.ContainerImage = common.DefaultPodImage
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: args.GenerateName,
|
||||
Namespace: args.Namespace,
|
||||
Labels: map[string]string{
|
||||
createdByLabel: "yes",
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{{
|
||||
Name: args.GenerateName,
|
||||
Image: args.ContainerImage,
|
||||
Command: []string{"/bin/sh"},
|
||||
Args: []string{"-c", args.Cmd},
|
||||
VolumeMounts: []v1.VolumeMount{{
|
||||
Name: "persistent-storage",
|
||||
MountPath: "/data",
|
||||
}},
|
||||
}},
|
||||
Volumes: []v1.Volume{{
|
||||
Name: "persistent-storage",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
|
||||
ClaimName: args.PVCName,
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if args.RunAsUser > 0 {
|
||||
pod.Spec.SecurityContext = &v1.PodSecurityContext{
|
||||
RunAsUser: &args.RunAsUser,
|
||||
FSGroup: &args.RunAsUser,
|
||||
}
|
||||
}
|
||||
|
||||
podRes, err := c.kubeCli.CoreV1().Pods(args.Namespace).Create(ctx, pod, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return pod, err
|
||||
}
|
||||
return podRes, nil
|
||||
}
|
||||
|
||||
func (c *applicationCreate) WaitForPodReady(ctx context.Context, namespace string, podName string) error {
|
||||
if c.kubeCli == nil {
|
||||
return fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
err := kankube.WaitForPodReady(ctx, c.kubeCli, namespace, podName)
|
||||
return err
|
||||
}
|
||||
|
||||
//go:generate mockgen -destination=mocks/mock_snapshot_creator.go -package=mocks . SnapshotCreator
|
||||
type SnapshotCreator interface {
|
||||
NewSnapshotter() (kansnapshot.Snapshotter, error)
|
||||
CreateSnapshot(ctx context.Context, snapshotter kansnapshot.Snapshotter, args *types.CreateSnapshotArgs) (*snapv1.VolumeSnapshot, error)
|
||||
CreateFromSourceCheck(ctx context.Context, snapshotter kansnapshot.Snapshotter, args *types.CreateFromSourceCheckArgs, SnapshotGroupVersion *metav1.GroupVersionForDiscovery) error
|
||||
}
|
||||
|
||||
type snapshotCreate struct {
|
||||
kubeCli kubernetes.Interface
|
||||
dynCli dynamic.Interface
|
||||
}
|
||||
|
||||
func (c *snapshotCreate) NewSnapshotter() (kansnapshot.Snapshotter, error) {
|
||||
if c.kubeCli == nil {
|
||||
return nil, fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
if c.dynCli == nil {
|
||||
return nil, fmt.Errorf("dynCli not initialized")
|
||||
}
|
||||
return kansnapshot.NewSnapshotter(c.kubeCli, c.dynCli)
|
||||
}
|
||||
|
||||
func (c *snapshotCreate) CreateSnapshot(ctx context.Context, snapshotter kansnapshot.Snapshotter, args *types.CreateSnapshotArgs) (*snapv1.VolumeSnapshot, error) {
|
||||
if snapshotter == nil || args == nil {
|
||||
return nil, fmt.Errorf("snapshotter or args are empty")
|
||||
}
|
||||
if err := args.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err := snapshotter.Create(ctx, args.SnapshotName, args.Namespace, args.PVCName, &args.VolumeSnapshotClass, true, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "CSI Driver failed to create snapshot for PVC (%s) in Namespace (%s)", args.PVCName, args.Namespace)
|
||||
}
|
||||
snap, err := snapshotter.Get(ctx, args.SnapshotName, args.Namespace)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to get CSI snapshot (%s) in Namespace (%s)", args.SnapshotName, args.Namespace)
|
||||
}
|
||||
return snap, nil
|
||||
}
|
||||
|
||||
func (c *snapshotCreate) CreateFromSourceCheck(ctx context.Context, snapshotter kansnapshot.Snapshotter, args *types.CreateFromSourceCheckArgs, SnapshotGroupVersion *metav1.GroupVersionForDiscovery) error {
|
||||
if c.dynCli == nil {
|
||||
return fmt.Errorf("dynCli not initialized")
|
||||
}
|
||||
if SnapshotGroupVersion == nil || SnapshotGroupVersion.Version == "" {
|
||||
return fmt.Errorf("snapshot group version not provided")
|
||||
}
|
||||
if snapshotter == nil || args == nil {
|
||||
return fmt.Errorf("snapshotter or args are nil")
|
||||
}
|
||||
if err := args.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
targetSnapClassName := clonePrefix + args.VolumeSnapshotClass
|
||||
err := snapshotter.CloneVolumeSnapshotClass(ctx, args.VolumeSnapshotClass, targetSnapClassName, kansnapshot.DeletionPolicyRetain, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Failed to create a VolumeSnapshotClass to use to restore the snapshot")
|
||||
}
|
||||
defer func() {
|
||||
VolSnapClassGVR := schema.GroupVersionResource{Group: common.SnapGroupName, Version: SnapshotGroupVersion.Version, Resource: common.VolumeSnapshotClassResourcePlural}
|
||||
err := c.dynCli.Resource(VolSnapClassGVR).Delete(ctx, targetSnapClassName, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
fmt.Printf("Delete VSC Error (%s) - (%v)\n", targetSnapClassName, err)
|
||||
}
|
||||
}()
|
||||
|
||||
snapSrc, err := snapshotter.GetSource(ctx, args.SnapshotName, args.Namespace)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Failed to get source snapshot source (%s)", args.SnapshotName)
|
||||
}
|
||||
snapshotCFSCloneName := clonePrefix + args.SnapshotName
|
||||
// test the CreateFromSource API
|
||||
defer func() {
|
||||
_, _ = snapshotter.Delete(context.Background(), snapshotCFSCloneName, args.Namespace)
|
||||
}()
|
||||
src := &kansnapshot.Source{
|
||||
Handle: snapSrc.Handle,
|
||||
Driver: snapSrc.Driver,
|
||||
VolumeSnapshotClassName: targetSnapClassName,
|
||||
}
|
||||
err = snapshotter.CreateFromSource(ctx, src, snapshotCFSCloneName, args.Namespace, true)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Failed to clone snapshot from source (%s)", snapshotCFSCloneName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:generate mockgen -destination=mocks/mock_cleaner.go -package=mocks . Cleaner
|
||||
type Cleaner interface {
|
||||
DeletePVC(ctx context.Context, pvcName string, namespace string) error
|
||||
DeletePod(ctx context.Context, podName string, namespace string) error
|
||||
DeleteSnapshot(ctx context.Context, snapshotName string, namespace string, SnapshotGroupVersion *metav1.GroupVersionForDiscovery) error
|
||||
}
|
||||
|
||||
type cleanse struct {
|
||||
kubeCli kubernetes.Interface
|
||||
dynCli dynamic.Interface
|
||||
}
|
||||
|
||||
func (c *cleanse) DeletePVC(ctx context.Context, pvcName string, namespace string) error {
|
||||
if c.kubeCli == nil {
|
||||
return fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
return c.kubeCli.CoreV1().PersistentVolumeClaims(namespace).Delete(ctx, pvcName, metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
func (c *cleanse) DeletePod(ctx context.Context, podName string, namespace string) error {
|
||||
if c.kubeCli == nil {
|
||||
return fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
return c.kubeCli.CoreV1().Pods(namespace).Delete(ctx, podName, metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
func (c *cleanse) DeleteSnapshot(ctx context.Context, snapshotName string, namespace string, SnapshotGroupVersion *metav1.GroupVersionForDiscovery) error {
|
||||
if c.dynCli == nil {
|
||||
return fmt.Errorf("dynCli not initialized")
|
||||
}
|
||||
if SnapshotGroupVersion == nil || SnapshotGroupVersion.Version == "" {
|
||||
return fmt.Errorf("snapshot group version not provided")
|
||||
}
|
||||
VolSnapGVR := schema.GroupVersionResource{Group: common.SnapGroupName, Version: SnapshotGroupVersion.Version, Resource: common.VolumeSnapshotResourcePlural}
|
||||
return c.dynCli.Resource(VolSnapGVR).Namespace(namespace).Delete(ctx, snapshotName, metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
//go:generate mockgen -destination=mocks/mock_api_version_fetcher.go -package=mocks . ApiVersionFetcher
|
||||
type ApiVersionFetcher interface {
|
||||
GetCSISnapshotGroupVersion() (*metav1.GroupVersionForDiscovery, error)
|
||||
}
|
||||
|
||||
type apiVersionFetch struct {
|
||||
kubeCli kubernetes.Interface
|
||||
}
|
||||
|
||||
func (p *apiVersionFetch) GetCSISnapshotGroupVersion() (*metav1.GroupVersionForDiscovery, error) {
|
||||
if p.kubeCli == nil {
|
||||
return nil, fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
groups, _, err := p.kubeCli.Discovery().ServerGroupsAndResources()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, group := range groups {
|
||||
if group.Name == common.SnapGroupName {
|
||||
return &group.PreferredVersion, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("Snapshot API group not found")
|
||||
}
|
||||
|
||||
//go:generate mockgen -destination=mocks/mock_data_validator.go -package=mocks . DataValidator
|
||||
type DataValidator interface {
|
||||
FetchPodData(podName string, podNamespace string) (string, error)
|
||||
}
|
||||
|
||||
type validateData struct {
|
||||
kubeCli kubernetes.Interface
|
||||
}
|
||||
|
||||
func (p *validateData) FetchPodData(podName string, podNamespace string) (string, error) {
|
||||
if p.kubeCli == nil {
|
||||
return "", fmt.Errorf("kubeCli not initialized")
|
||||
}
|
||||
stdout, _, err := kankube.Exec(p.kubeCli, podNamespace, podName, "", []string{"sh", "-c", "cat /data/out.txt"}, nil)
|
||||
return stdout, err
|
||||
}
|
||||
|
||||
func getDriverNameFromUVSC(vsc unstructured.Unstructured, version string) string {
|
||||
var driverName interface{}
|
||||
var ok bool
|
||||
|
|
|
@ -232,9 +232,11 @@ func (s *CSITestSuite) TestCreateApplication(c *C) {
|
|||
GenerateName: originalPodGenerateName,
|
||||
PVCName: "pvc1",
|
||||
Namespace: "ns",
|
||||
Cmd: "echo 'some string' >> /data/out.txt; sync; tail -f /dev/null",
|
||||
Command: []string{"/bin/sh"},
|
||||
ContainerArgs: []string{"-c", "echo 'some string' >> /data/out.txt; sync; tail -f /dev/null"},
|
||||
RunAsUser: 100,
|
||||
ContainerImage: "image",
|
||||
MountPath: "/data",
|
||||
}).Return(&v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod1",
|
||||
|
@ -270,9 +272,11 @@ func (s *CSITestSuite) TestCreateApplication(c *C) {
|
|||
GenerateName: originalPodGenerateName,
|
||||
PVCName: "pvc1",
|
||||
Namespace: "ns",
|
||||
Cmd: "echo 'some string' >> /data/out.txt; sync; tail -f /dev/null",
|
||||
Command: []string{"/bin/sh"},
|
||||
ContainerArgs: []string{"-c", "echo 'some string' >> /data/out.txt; sync; tail -f /dev/null"},
|
||||
RunAsUser: 100,
|
||||
ContainerImage: "image",
|
||||
MountPath: "/data",
|
||||
}).Return(&v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod1",
|
||||
|
@ -573,7 +577,9 @@ func (s *CSITestSuite) TestRestoreApplication(c *C) {
|
|||
GenerateName: clonedPodGenerateName,
|
||||
PVCName: "pvc1",
|
||||
Namespace: "ns",
|
||||
Cmd: "tail -f /dev/null",
|
||||
Command: []string{"/bin/sh"},
|
||||
ContainerArgs: []string{"-c", "tail -f /dev/null"},
|
||||
MountPath: "/data",
|
||||
RunAsUser: 100,
|
||||
ContainerImage: "image",
|
||||
}).Return(&v1.Pod{
|
||||
|
@ -624,7 +630,9 @@ func (s *CSITestSuite) TestRestoreApplication(c *C) {
|
|||
GenerateName: clonedPodGenerateName,
|
||||
PVCName: "pvc1",
|
||||
Namespace: "ns",
|
||||
Cmd: "tail -f /dev/null",
|
||||
Command: []string{"/bin/sh"},
|
||||
ContainerArgs: []string{"-c", "tail -f /dev/null"},
|
||||
MountPath: "/data",
|
||||
RunAsUser: 100,
|
||||
ContainerImage: "image",
|
||||
}).Return(&v1.Pod{
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
snapv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type CSISnapshotRestoreArgs struct {
|
||||
|
@ -52,13 +54,15 @@ type CreatePodArgs struct {
|
|||
GenerateName string
|
||||
PVCName string
|
||||
Namespace string
|
||||
Cmd string
|
||||
RunAsUser int64
|
||||
ContainerImage string
|
||||
Command []string
|
||||
ContainerArgs []string
|
||||
MountPath string
|
||||
}
|
||||
|
||||
func (c *CreatePodArgs) Validate() error {
|
||||
if c.GenerateName == "" || c.PVCName == "" || c.Namespace == "" || c.Cmd == "" {
|
||||
if c.GenerateName == "" || c.PVCName == "" || c.Namespace == "" {
|
||||
return fmt.Errorf("Invalid CreatePodArgs (%v)", c)
|
||||
}
|
||||
return nil
|
||||
|
@ -90,3 +94,36 @@ func (c *CreateFromSourceCheckArgs) Validate() error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PVCBrowseArgs struct {
|
||||
PVCName string
|
||||
Namespace string
|
||||
VolumeSnapshotClass string
|
||||
RunAsUser int64
|
||||
LocalPort int
|
||||
}
|
||||
|
||||
func (p *PVCBrowseArgs) Validate() error {
|
||||
if p.PVCName == "" || p.Namespace == "" || p.VolumeSnapshotClass == "" {
|
||||
return fmt.Errorf("Invalid PVCBrowseArgs (%v)", p)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PortForwardAPodRequest struct {
|
||||
// RestConfig is the kubernetes config
|
||||
RestConfig *rest.Config
|
||||
// Pod is the selected pod for this port forwarding
|
||||
Pod *v1.Pod
|
||||
// LocalPort is the local port that will be selected to expose the PodPort
|
||||
LocalPort int
|
||||
// PodPort is the target port for the pod
|
||||
PodPort int
|
||||
// Streams configures where to write or read input from
|
||||
OutStream bytes.Buffer
|
||||
ErrOutStream bytes.Buffer
|
||||
// StopCh is the channel used to manage the port forward lifecycle
|
||||
StopCh <-chan struct{}
|
||||
// ReadyCh communicates when the tunnel is ready to receive traffic
|
||||
ReadyCh chan struct{}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,10 @@ var CSIDriverList = []*CSIDriver{
|
|||
{NameUrl: "[Bigtera VirtualStor (block)](https://github.com/bigtera-ce/ceph-csi)", DriverName: "csi.block.bigtera.com", Versions: "v0.3, v1.0.0, v1.1.0", Description: "A Container Storage Interface (CSI) Driver for Bigtera VirtualStor block storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion"},
|
||||
{NameUrl: "[Bigtera VirtualStor (filesystem)](https://github.com/bigtera-ce/ceph-csi)", DriverName: "csi.fs.bigtera.com", Versions: "v0.3, v1.0.0, v1.1.0", Description: "A Container Storage Interface (CSI) Driver for Bigtera VirtualStor filesystem", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Expansion"},
|
||||
{NameUrl: "[BizFlyCloud Block Storage](https://github.com/bizflycloud/csi-bizflycloud)", DriverName: "volume.csi.bizflycloud.vn", Versions: "v1.2", Description: "A Container Storage Interface (CSI) Driver for BizFly Cloud block storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion"},
|
||||
{NameUrl: "[CephFS](https://github.com/ceph/ceph-csi)", DriverName: "cephfs.csi.ceph.com", Versions: "v0.3, v1.0.0, v1.1.0, v1.2.0", Description: "A Container Storage Interface (CSI) Driver for CephFS", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Expansion, Snapshot, Clone"},
|
||||
{NameUrl: "[Ceph RBD](https://github.com/ceph/ceph-csi)", DriverName: "rbd.csi.ceph.com", Versions: "v0.3, v1.0.0, v1.1.0, v1.2.0", Description: "A Container Storage Interface (CSI) Driver for Ceph RBD", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Topology, Cloning"},
|
||||
{NameUrl: "[CephFS](https://github.com/ceph/ceph-csi)", DriverName: "cephfs.csi.ceph.com", Versions: "v0.3, >=v1.0.0", Description: "A Container Storage Interface (CSI) Driver for CephFS", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Expansion, Snapshot, Cloning"},
|
||||
{NameUrl: "[Ceph RBD](https://github.com/ceph/ceph-csi)", DriverName: "rbd.csi.ceph.com", Versions: "v0.3, >=v1.0.0", Description: "A Container Storage Interface (CSI) Driver for Ceph RBD", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Topology, Cloning"},
|
||||
{NameUrl: "[ChubaoFS](https://github.com/chubaofs/chubaofs-csi)", DriverName: "csi.chubaofs.com", Versions: "v1.0.0", Description: "A Container Storage Interface (CSI) Driver for ChubaoFS Storage", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: ""},
|
||||
{NameUrl: "[Cinder](https://github.com/kubernetes/cloud-provider-openstack/tree/master/pkg/csi/cinder)", DriverName: "cinder.csi.openstack.org", Versions: "v0.3, v1.0, v1.1", Description: "A Container Storage Interface (CSI) Driver for OpenStack Cinder", Persistence: "Persistent and Ephemeral", AccessModes: "Depends on the storage backend used", DynamicProvisioning: "Yes, if storage backend supports it", Features: "Raw Block, Snapshot, Expansion"},
|
||||
{NameUrl: "[Cinder](https://github.com/kubernetes/cloud-provider-openstack/tree/master/pkg/csi/cinder)", DriverName: "cinder.csi.openstack.org", Versions: "v0.3, v1.0, v1.1.0, v1.2.0, v1.3.0", Description: "A Container Storage Interface (CSI) Driver for OpenStack Cinder", Persistence: "Persistent and Ephemeral", AccessModes: "Depends on the storage backend used", DynamicProvisioning: "Yes, if storage backend supports it", Features: "Raw Block, Snapshot, Expansion, Cloning, Topology"},
|
||||
{NameUrl: "[cloudscale.ch](https://github.com/cloudscale-ch/csi-cloudscale)", DriverName: "csi.cloudscale.ch", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for the [cloudscale.ch](https://www.cloudscale.ch/) IaaS platform", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Snapshot"},
|
||||
{NameUrl: "[Datatom-InfinityCSI](https://github.com/datatom-infinity/infinity-csi)", DriverName: "csi-infiblock-plugin", Versions: "v0.3, v1.0.0, v1.1.0", Description: "A Container Storage Interface (CSI) Driver for DATATOM Infinity storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Topology"},
|
||||
{NameUrl: "[Datatom-InfinityCSI (filesystem)](https://github.com/datatom-infinity/infinity-csi)", DriverName: "csi-infifs-plugin", Versions: "v0.3, v1.0.0, v1.1.0", Description: "A Container Storage Interface (CSI) Driver for DATATOM Infinity filesystem storage", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Expansion"},
|
||||
|
@ -32,11 +32,10 @@ var CSIDriverList = []*CSIDriver{
|
|||
{NameUrl: "[Dell EMC PowerStore](https://github.com/dell/csi-powerstore)", DriverName: "csi-powerstore.dellemc.com", Versions: "v1.1", Description: "A Container Storage Interface (CSI) Driver for [Dell EMC PowerStore](https://www.delltechnologies.com/en-us/storage/powerstore-storage-appliance.htm)", Persistence: "Persistent and Ephemeral", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning, Topology"},
|
||||
{NameUrl: "[Dell EMC Unity](https://github.com/dell/csi-unity)", DriverName: "csi-unity.dellemc.com", Versions: "v1.1", Description: "A Container Storage Interface (CSI) Driver for [Dell EMC Unity](https://www.delltechnologies.com/en-us/storage/unity.htm)", Persistence: "Persistent and Ephemeral", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning, Topology"},
|
||||
{NameUrl: "[Dell EMC VxFlexOS](https://github.com/dell/csi-vxflexos)", DriverName: "csi-vxflexos.dellemc.com", Versions: "v1.1", Description: "A Container Storage Interface (CSI) Driver for [Dell EMC VxFlexOS](https://www.delltechnologies.com/en-us/hyperconverged-infrastructure/vxflex.htm)", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning, Topology"},
|
||||
{NameUrl: "[democratic-csi](https://github.com/democratic-csi/democratic-csi)", DriverName: "org.democratic-csi", Versions: "v1.0,v1.1,v1.2", Description: "Generic CSI plugin supporting zfs based solutions ([FreeNAS](https://www.freenas.org/) / [TrueNAS](https://www.truenas.com/) and [ZoL](https://zfsonlinux.org/) solutions such as [Ubuntu](https://ubuntu.com/))", Persistence: "Persistent and Ephemeral", AccessModes: "Read/Write Single Pod (Block Volume) <br/><br/> Read/Write Multiple Pods (File Volume)", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[democratic-csi](https://github.com/democratic-csi/democratic-csi)", DriverName: "org.democratic-csi", Versions: "v1.0,v1.1,v1.2,v1.3,v1.4,v1.5", Description: "Generic CSI plugin supporting zfs based solutions ([FreeNAS](https://www.freenas.org/) / [TrueNAS](https://www.truenas.com/) and [ZoL](https://zfsonlinux.org/) solutions such as [Ubuntu](https://ubuntu.com/)), [Synology](https://www.synology.com/), and more", Persistence: "Persistent and Ephemeral", AccessModes: "Read/Write Single Pod (Block Volume) <br/><br/> Read/Write Multiple Pods (File Volume)", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[Diamanti-CSI](https://diamanti.com/use-cases/io-acceleration/#csi)", DriverName: "dcx.csi.diamanti.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for Diamanti DCX Platform", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion"},
|
||||
{NameUrl: "[DigitalOcean Block Storage](https://github.com/digitalocean/csi-digitalocean)", DriverName: "dobs.csi.digitalocean.com", Versions: "v0.3, v1.0", Description: "A Container Storage Interface (CSI) Driver for DigitalOcean Block Storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion"},
|
||||
{NameUrl: "[Dothill-CSI](https://github.com/enix/dothill-csi)", DriverName: "dothill.csi.enix.io", Versions: "v1.3", Description: "Generic CSI plugin supporting [Seagate AssuredSan](https://www.seagate.com/fr/fr/support/dothill-san/assuredsan-pro-5000-series/) appliances such as [HPE MSA](https://www.hpe.com/us/en/storage/flash-hybrid.html), [Dell EMC PowerVault ME4](https://www.dell.com/fr-fr/work/shop/productdetailstxn/powervault-me4-series) and others ...", Persistence: "Persistent", AccessModes: "Read/Write Single Node", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion"},
|
||||
{NameUrl: "[DriveScale](https://github.com/DriveScale/k8s-plugins)", DriverName: "csi.drivescale.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for DriveScale software composable infrastructure solution", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: ""},
|
||||
{NameUrl: "[Ember CSI](https://ember-csi.io)", DriverName: "ember-csi.io", Versions: "v0.2, v0.3, v1.0", Description: "Multi-vendor CSI plugin supporting over 80 Drivers to provide block and mount storage to Container Orchestration systems.", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot"},
|
||||
{NameUrl: "[Excelero NVMesh](https://github.com/Excelero/nvmesh-csi-driver)", DriverName: "nvmesh-csi.excelero.com", Versions: "v1.0, v1.1", Description: "A Container Storage Interface (CSI) Driver for Excelero NVMesh", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Raw Block, Expansion"},
|
||||
{NameUrl: "[GCE Persistent Disk](https://github.com/kubernetes-sigs/gcp-compute-persistent-disk-csi-driver)", DriverName: "pd.csi.storage.gke.io", Versions: "v0.3, v1.0", Description: "A Container Storage Interface (CSI) Driver for Google Compute Engine Persistent Disk (GCE PD)", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Topology"},
|
||||
|
@ -48,10 +47,11 @@ var CSIDriverList = []*CSIDriver{
|
|||
{NameUrl: "[Hedvig](https://documentation.commvault.com/commvault/hedvig/others/pdf/Hedvig_CSI_User_Guide.pdf)", DriverName: "io.hedvig.csi", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for Hedvig", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion"},
|
||||
{NameUrl: "[Hetzner Cloud Volumes CSI](https://github.com/hetznercloud/csi-driver)", DriverName: "csi.hetzner.cloud", Versions: "v0.3, v1.0", Description: "A Container Storage Interface (CSI) Driver for Hetzner Cloud Volumes", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Expansion"},
|
||||
{NameUrl: "[Hitachi Vantara](https://knowledge.hitachivantara.com/Documents/Adapters_and_Drivers/Storage_Adapters_and_Drivers/Containers)", DriverName: "hspc.csi.hitachi.com", Versions: "v1.2", Description: "A Container Storage Interface (CSI) Driver for VSP series Storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[HPE](https://github.com/hpe-storage/csi-driver)", DriverName: "csi.hpe.com", Versions: "v1.0, v1.1, v1.2", Description: "A [multi-platform](https://scod.hpedev.io/csi_driver) Container Storage Interface (CSI) driver. Supports [HPE Nimble Storage](https://hpe.com/storage/nimble), [HPE Primera](https://hpe.com/storage/primera) and [HPE 3PAR](https://hpe.com/storage/3par)", Persistence: "Persistent and Ephemeral", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[HPE](https://github.com/hpe-storage/csi-driver)", DriverName: "csi.hpe.com", Versions: "v1.3", Description: "A [multi-platform](https://scod.hpedev.io/csi_driver) Container Storage Interface (CSI) driver. Supports [HPE Alletra](https://hpe.com/storage/alletra), [Nimble Storage](https://hpe.com/storage/nimble), [Primera](https://hpe.com/storage/primera) and [3PAR](https://hpe.com/storage/3par)", Persistence: "Persistent and Ephemeral", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[HPE Ezmeral (MapR)](https://github.com/mapr/mapr-csi)", DriverName: "com.mapr.csi-kdf", Versions: "v1.3", Description: "A Container Storage Interface (CSI) Driver for HPE Ezmeral Data Fabric", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[Huawei Storage CSI](https://github.com/Huawei/eSDK_K8S_Plugin)", DriverName: "csi.huawei.com", Versions: "v1.0, v1.1, v1.2", Description: "A Container Storage Interface (CSI) Driver for FusionStorage, OceanStor 100D, OceanStor Pacific, OceanStor Dorado V3, OceanStor Dorado V6, OceanStor V3, OceanStor V5", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pod", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[HyperV CSI](https://github.com/Zetanova/hyperv-csi-driver)", DriverName: "eu.zetanova.csi.hyperv", Versions: "v1.0, v1.1", Description: "A Container Storage Interface (CSI) driver to manage hyperv hosts", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: ""},
|
||||
{NameUrl: "[IBM Block Storage](https://github.com/ibm/ibm-block-csi-driver)", DriverName: "block.csi.ibm.com", Versions: "v1.0, v1.1, v1.2", Description: "A Container Storage Interface (CSI) [Driver](https://www.ibm.com/support/knowledgecenter/SSRQ8T) for IBM Spectrum Virtualize Family, IBM FlashSystem A9000 and A9000R, IBM DS8880 and DS8900.", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[IBM Block Storage](https://github.com/ibm/ibm-block-csi-driver)", DriverName: "block.csi.ibm.com", Versions: "v1.0, v1.1, v1.2", Description: "A Container Storage Interface (CSI) [Driver](https://www.ibm.com/docs/en/stg-block-csi-driver) for IBM Spectrum Virtualize Family, IBM FlashSystem A9000 and A9000R, IBM DS8000 Family 8.x and higher.", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning, Topology"},
|
||||
{NameUrl: "[IBM Spectrum Scale](https://github.com/IBM/ibm-spectrum-scale-csi)", DriverName: "spectrumscale.csi.ibm.com", Versions: "v1.0, v1.1", Description: "A Container Storage Interface (CSI) [Driver](https://www.ibm.com/docs/en/spectrum-scale-csi) for the IBM Spectrum Scale File System", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pod", DynamicProvisioning: "Yes", Features: "Snapshot"},
|
||||
{NameUrl: "[IBM Cloud Block Storage VPC CSI Driver](https://cloud.ibm.com/docs/containers?topic=containers-vpc-block)", DriverName: "vpc.block.csi.ibm.io", Versions: "v1.0", Description: "A Container Storage Interface (CSI) [Driver](https://cloud.ibm.com/docs/containers?topic=containers-vpc-block) for IBM Cloud Kubernetes Service and Red Hat OpenShift on IBM Cloud", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block"},
|
||||
{NameUrl: "[Infinidat](https://github.com/Infinidat/infinibox-csi-driver)", DriverName: "infinibox-csi-driver", Versions: "v1.0, v1.1", Description: "A Container Storage Interface (CSI) Driver for Infinidat [InfiniBox](https://infinidat.com/en/products-technology/infinibox)", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
|
@ -59,25 +59,26 @@ var CSIDriverList = []*CSIDriver{
|
|||
{NameUrl: "[Intel PMEM-CSI](https://github.com/intel/pmem-csi)", DriverName: "pmem-csi.intel.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) driver for [PMEM](https://pmem.io/) from Intel", Persistence: "Persistent and Ephemeral", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block"},
|
||||
{NameUrl: "[Intelliflash Block Storage](https://github.com/DDNStorage/intelliflash-csi-block-driver)", DriverName: "intelliflash-csi-block-driver.intelliflash.com", Versions: "v1.0, v1.1, v1.2", Description: "A Container Storage Interface (CSI) Driver for Intelliflash Block Storage", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion, Cloning, Topology"},
|
||||
{NameUrl: "[Intelliflash File Storage](https://github.com/DDNStorage/intelliflash-csi-file-driver)", DriverName: "intelliflash-csi-file-driver.intelliflash.com", Versions: "v1.0, v1.1, v1.2", Description: "A Container Storage Interface (CSI) Driver for Intelliflash File Storage", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion, Cloning, Topology"},
|
||||
{NameUrl: "[ionir ](https://github.com/ionir-cloud)", DriverName: "ionir", Versions: "v1.2", Description: "A Container Storage Interface (CSI) Driver for [ionir](https://www.ionir.com/) Kubernetes-Native Storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Cloning"},
|
||||
{NameUrl: "[JuiceFS](https://github.com/juicedata/juicefs-csi-driver)", DriverName: "csi.juicefs.com", Versions: "v0.3, v1.0", Description: "A Container Storage Interface (CSI) Driver for JuiceFS File System", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pod", DynamicProvisioning: "Yes", Features: ""},
|
||||
{NameUrl: "[kaDalu](https://github.com/kadalu/kadalu)", DriverName: "org.kadalu.gluster", Versions: "v0.3", Description: "A CSI Driver (and operator) for GlusterFS", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: ""},
|
||||
{NameUrl: "[KumoScale Block Storage](https://github.com/KioxiaAmerica/kumoscale-csi)", DriverName: "kumoscale.kioxia.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for KumoScale Block Storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Topology"},
|
||||
{NameUrl: "[Linode Block Storage](https://github.com/linode/linode-blockstorage-csi-driver)", DriverName: "linodebs.csi.linode.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for Linode Block Storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: ""},
|
||||
{NameUrl: "[LINSTOR](https://github.com/piraeusdatastore/linstor-csi)", DriverName: "linstor.csi.linbit.com", Versions: "v1.2", Description: "A Container Storage Interface (CSI) Driver for [LINSTOR](https://www.linbit.com/en/linstor/) volumes", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning, Topology"},
|
||||
{NameUrl: "[Longhorn](https://github.com/longhorn/longhorn)", DriverName: "driver.longhorn.io", Versions: "v1.1", Description: "A Container Storage Interface (CSI) Driver for [Longhorn](https://longhorn.io/) volumes", Persistence: "Persistent", AccessModes: "Read/Write Single Node", DynamicProvisioning: "Yes", Features: "Raw Block"},
|
||||
{NameUrl: "[Longhorn](https://github.com/longhorn/longhorn)", DriverName: "driver.longhorn.io", Versions: "v1.2", Description: "A Container Storage Interface (CSI) Driver for [Longhorn](https://longhorn.io/) volumes", Persistence: "Persistent", AccessModes: "Read/Write Single Node", DynamicProvisioning: "Yes", Features: "Raw Block"},
|
||||
{NameUrl: "[MacroSAN](https://github.com/macrosan-csi/macrosan-csi-driver)", DriverName: "csi-macrosan", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for MacroSAN Block Storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: ""},
|
||||
{NameUrl: "[Manila](https://github.com/kubernetes/cloud-provider-openstack/tree/master/pkg/csi/manila)", DriverName: "manila.csi.openstack.org", Versions: "v1.1, v1.2", Description: "A Container Storage Interface (CSI) Driver for OpenStack Shared File System Service (Manila)", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot, Topology"},
|
||||
{NameUrl: "[MapR](https://github.com/mapr/mapr-csi)", DriverName: "com.mapr.csi-kdf", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for MapR Data Platform", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot"},
|
||||
{NameUrl: "[MooseFS](https://github.com/moosefs/moosefs-csi)", DriverName: "com.tuxera.csi.moosefs", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for [MooseFS](https://moosefs.com/) clusters.", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: ""},
|
||||
{NameUrl: "[NetApp](https://github.com/NetApp/trident)", DriverName: "csi.trident.netapp.io", Versions: "v1.0, v1.1, v1.2", Description: "A Container Storage Interface (CSI) Driver for NetApp's [Trident](https://netapp-trident.readthedocs.io/) container storage orchestrator", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning, Topology"},
|
||||
{NameUrl: "[NetApp](https://github.com/NetApp/trident)", DriverName: "csi.trident.netapp.io", Versions: "v1.0, v1.1, v1.2, v1.3", Description: "A Container Storage Interface (CSI) Driver for NetApp's [Trident](https://netapp-trident.readthedocs.io/) container storage orchestrator", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning, Topology"},
|
||||
{NameUrl: "[NexentaStor File Storage](https://github.com/Nexenta/nexentastor-csi-driver)", DriverName: "nexentastor-csi-driver.nexenta.com", Versions: "v1.0, v1.1, v1.2", Description: "A Container Storage Interface (CSI) Driver for NexentaStor File Storage", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion, Cloning, Topology"},
|
||||
{NameUrl: "[NexentaStor Block Storage](https://github.com/Nexenta/nexentastor-csi-driver-block)", DriverName: "nexentastor-block-csi-driver.nexenta.com", Versions: "v1.0, v1.1, v1.2", Description: "A Container Storage Interface (CSI) Driver for NexentaStor over iSCSI protocol", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion, Cloning, Topology, Raw block"},
|
||||
{NameUrl: "[Nutanix](https://github.com/nutanix/csi-plugin)", DriverName: "com.nutanix.csi", Versions: "v0.3, v1.0, v1.2", Description: "A Container Storage Interface (CSI) Driver for Nutanix", Persistence: "Persistent", AccessModes: "Read/Write Single Pod with Nutanix Volumes and Read/Write Multiple Pods with Nutanix Files", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[OpenEBS](https://github.com/openebs/csi)", DriverName: "cstor.csi.openebs.io", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for [OpenEBS](https://www.openebs.io/)", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Expansion, Snapshot, Cloning"},
|
||||
{NameUrl: "[Open-E](https://github.com/open-e/JovianDSS-KubernetesCSI)", DriverName: "com.open-e.joviandss.csi", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for Open-E JovianDSS Storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Snapshot, Cloning"},
|
||||
{NameUrl: "[Open-Local](https://github.com/alibaba/open-local)", DriverName: "local.csi.alibaba.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for Local Storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Expansion, Snapshot"},
|
||||
{NameUrl: "[Oracle Cloud Infrastructure(OCI) Block Storage](https://github.com/oracle/oci-cloud-controller-manager/blob/master/container-storage-interface.md)", DriverName: "blockvolume.csi.oraclecloud.com", Versions: "v1.1", Description: "A Container Storage Interface (CSI) Driver for Oracle Cloud Infrastructure (OCI) Block Storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Topology"},
|
||||
{NameUrl: "[oVirt](https://github.com/openshift/ovirt-csi-driver)", DriverName: "csi.ovirt.org", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for [oVirt](https://ovirt.org)", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Block, File Storage"},
|
||||
{NameUrl: "[Portworx](https://github.com/libopenstorage/openstorage/tree/master/csi)", DriverName: "pxd.openstorage.org", Versions: "v0.3, v1.1", Description: "A Container Storage Interface (CSI) Driver for [Portworx](https://docs.portworx.com/portworx-install-with-kubernetes/storage-operations/csi/)", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion"},
|
||||
{NameUrl: "[Portworx](https://github.com/libopenstorage/openstorage/tree/master/csi)", DriverName: "pxd.portworx.com", Versions: "v1.4", Description: "A Container Storage Interface (CSI) Driver for [Portworx](https://docs.portworx.com/portworx-install-with-kubernetes/storage-operations/csi/)", Persistence: "Persistent and Ephemeral", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion, Raw Block, Cloning"},
|
||||
{NameUrl: "[Pure Storage CSI](https://github.com/purestorage/pso-csi)", DriverName: "pure-csi", Versions: "v1.0, v1.1, v1.2, v1.3", Description: "A Container Storage Interface (CSI) Driver for Pure Storage's [Pure Service Orchestrator](https://purestorage.com/containers)", Persistence: "Persistent and Ephemeral", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot, Cloning, Raw Block, Topology, Expansion"},
|
||||
{NameUrl: "[QingCloud CSI](https://github.com/yunify/qingcloud-csi)", DriverName: "disk.csi.qingcloud.com", Versions: "v1.1", Description: "A Container Storage Interface (CSI) Driver for QingCloud Block Storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[QingStor CSI](https://github.com/yunify/qingstor-csi)", DriverName: "neonsan.csi.qingstor.com", Versions: "v0.3, v1.1", Description: "A Container Storage Interface (CSI) Driver for NeonSAN storage system", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
|
@ -87,7 +88,8 @@ var CSIDriverList = []*CSIDriver{
|
|||
{NameUrl: "[Sangfor-EDS-File-Storage](https://github.com/evan37717/sangfor-eds-csi)", DriverName: "eds.csi.file.sangfor.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for Sangfor Distributed File Storage(EDS)", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[Sangfor-EDS-Block-Storage](https://github.com/eds-wzc/sangfor-eds-csi)", DriverName: "eds.csi.block.sangfor.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for Sangfor Block Storage(EDS)", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[Scaleway CSI](https://github.com/scaleway/scaleway-csi)", DriverName: "csi.scaleway.com", Versions: "v1.2.0", Description: "Container Storage Interface (CSI) Driver for [Scaleway Block Storage](https://www.scaleway.com/block-storage/)", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Topology"},
|
||||
{NameUrl: "[SeaweedFS](https://github.com/seaweedfs/seaweedfs-csi-driver)", DriverName: "seaweedfs-csi-driver", Versions: "v1.0", Description: "A Container Storage Interface (CSI Driver for [SeaweedFS](https://github.com/chrislusf/seaweedfs))", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Topology"},
|
||||
{NameUrl: "[Seagate Exos X](https://github.com/Seagate/seagate-exos-x-csi)", DriverName: "csi-exos-x.seagate.com", Versions: "v1.3", Description: "CSI driver for [Seagate Exos X](https://www.seagate.com/products/storage/data-storage-systems/raid/) and OEM systems", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[SeaweedFS](https://github.com/seaweedfs/seaweedfs-csi-driver)", DriverName: "seaweedfs-csi-driver", Versions: "v1.0", Description: "A Container Storage Interface (CSI Driver for [SeaweedFS](https://github.com/chrislusf/seaweedfs))", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[Secrets Store CSI Driver](https://github.com/kubernetes-sigs/secrets-store-csi-driver)", DriverName: "secrets-store.csi.k8s.io", Versions: "v0.0.10", Description: "A Container Storage Interface (CSI) Driver for mounting secrets, keys, and certs stored in enterprise-grade external secrets stores as volumes.", Persistence: "Ephemeral", AccessModes: "N/A", DynamicProvisioning: "N/A", Features: ""},
|
||||
{NameUrl: "[SmartX](http://www.smartx.com/?locale=en)", DriverName: "csi-smtx-plugin", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for SmartX ZBS Storage", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion"},
|
||||
{NameUrl: "[SODA](https://github.com/sodafoundation/nbp/tree/master/csi)", DriverName: "csi-soda-plugin", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for [SODA](https://sodafoundation.io/)", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot"},
|
||||
|
@ -95,6 +97,7 @@ var CSIDriverList = []*CSIDriver{
|
|||
{NameUrl: "[StorageOS](https://docs.storageos.com/docs/platforms/kubernetes/install/)", DriverName: "storageos", Versions: "v0.3, v1.0", Description: "A Container Storage Interface (CSI) Driver for [StorageOS](https://storageos.com/)", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot"},
|
||||
{NameUrl: "[Storidge](https://docs.storidge.com/kubernetes_storage/overview.html)", DriverName: "csi.cio.storidge.com", Versions: "v0.3, v1.0", Description: "A Container Storage Interface (CSI) Driver for [Storidge CIO](https://storidge.com/)", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion"},
|
||||
{NameUrl: "[StorPool](https://kb.storpool.com/storpool_integrations/github/kubernetes.html)", DriverName: "csi-driver.storpool.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for [StorPool](https://storpool.com/)", Persistence: "Persistent and Ephemeral", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Expansion"},
|
||||
{NameUrl: "[Synology](https://github.com/SynologyOpenSource/synology-csi)", DriverName: "csi.san.synology.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for Synology NAS", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[Tencent Cloud Block Storage](https://github.com/TencentCloud/kubernetes-csi-tencentcloud)", DriverName: "com.tencent.cloud.csi.cbs", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for Tencent Cloud Block Storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Snapshot"},
|
||||
{NameUrl: "[Tencent Cloud File Storage](https://github.com/TencentCloud/kubernetes-csi-tencentcloud)", DriverName: "com.tencent.cloud.csi.cfs", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for Tencent Cloud File Storage", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot"},
|
||||
{NameUrl: "[Tencent Cloud Object Storage](https://github.com/TencentCloud/kubernetes-csi-tencentcloud)", DriverName: "com.tencent.cloud.csi.cosfs", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for Tencent Cloud Object Storage", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "No", Features: "Snapshot"},
|
||||
|
@ -103,6 +106,7 @@ var CSIDriverList = []*CSIDriver{
|
|||
{NameUrl: "[XSKY-EBS](https://xsky-storage.github.io/xsky-csi-driver/csi-block.html)", DriverName: "csi.block.xsky.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for XSKY Distributed Block Storage (X-EBS)", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: "Raw Block, Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[XSKY-EUS](https://xsky-storage.github.io/xsky-csi-driver/csi-fs.html)", DriverName: "csi.fs.xsky.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for XSKY Distributed File Storage (X-EUS)", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: ""},
|
||||
{NameUrl: "[Vault](https://github.com/kubevault/csi-driver)", DriverName: "secrets.csi.kubevault.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for mounting HashiCorp Vault secrets as volumes.", Persistence: "Ephemeral", AccessModes: "N/A", DynamicProvisioning: "N/A", Features: ""},
|
||||
{NameUrl: "[VDA](https://virtual-disk-array.readthedocs.io/en/latest/Introduction.html)", DriverName: "csi.vda.io", Versions: "v1.0", Description: "An open source block storage system base on SPDK", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "N/A", Features: ""},
|
||||
{NameUrl: "[Veritas InfoScale Volumes](https://www.veritas.com/solution/virtualization/containers.html)", DriverName: "org.veritas.infoscale", Versions: "v1.2", Description: "A Container Storage Interface (CSI) Driver for Veritas InfoScale volumes", Persistence: "Persistent", AccessModes: "Read/Write Multiple Pods", DynamicProvisioning: "Yes", Features: "Snapshot, Expansion, Cloning"},
|
||||
{NameUrl: "[vSphere](https://github.com/kubernetes-sigs/vsphere-csi-driver)", DriverName: "csi.vsphere.vmware.com", Versions: "v1.0", Description: "A Container Storage Interface (CSI) Driver for VMware vSphere", Persistence: "Persistent", AccessModes: "Read/Write Single Pod (Block Volume) <br/><br/> Read/Write Multiple Pods (File Volume)", DynamicProvisioning: "Yes", Features: "Raw Block,<br/><br/>Expansion (Block Volume),<br/><br/>Topology Aware (Block Volume)"},
|
||||
{NameUrl: "[Vultr Block Storage](https://github.com/vultr/vultr-csi)", DriverName: "block.csi.vultr.com", Versions: "v1.2", Description: "A Container Storage Interface (CSI) Driver for Vultr Block Storage", Persistence: "Persistent", AccessModes: "Read/Write Single Pod", DynamicProvisioning: "Yes", Features: ""},
|
||||
|
|
Loading…
Reference in a new issue