mirror of https://github.com/k3s-io/k3s
Merge pull request #74283 from xing-yang/csi_crd_controller
CSINodeInfo and CSIDriver Controller Changespull/564/head
commit
6c31101257
File diff suppressed because it is too large
Load Diff
|
@ -134,7 +134,6 @@ go_library(
|
|||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/cli/flag:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/cli/globalflag:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library",
|
||||
"//staging/src/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/metrics/pkg/client/custom_metrics:go_default_library",
|
||||
"//staging/src/k8s.io/metrics/pkg/client/external_metrics:go_default_library",
|
||||
|
|
|
@ -37,7 +37,6 @@ import (
|
|||
"k8s.io/client-go/dynamic"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
cloudcontroller "k8s.io/kubernetes/pkg/controller/cloud"
|
||||
endpointcontroller "k8s.io/kubernetes/pkg/controller/endpoint"
|
||||
|
@ -216,14 +215,10 @@ func startAttachDetachController(ctx ControllerContext) (http.Handler, bool, err
|
|||
if ctx.ComponentConfig.AttachDetachController.ReconcilerSyncLoopPeriod.Duration < time.Second {
|
||||
return nil, true, fmt.Errorf("duration time must be greater than one second as set via command line option reconcile-sync-loop-period")
|
||||
}
|
||||
csiClientConfig := ctx.ClientBuilder.ConfigOrDie("attachdetach-controller")
|
||||
// csiClient works with CRDs that support json only
|
||||
csiClientConfig.ContentType = "application/json"
|
||||
|
||||
attachDetachController, attachDetachControllerErr :=
|
||||
attachdetach.NewAttachDetachController(
|
||||
ctx.ClientBuilder.ClientOrDie("attachdetach-controller"),
|
||||
csiclientset.NewForConfigOrDie(csiClientConfig),
|
||||
ctx.InformerFactory.Core().V1().Pods(),
|
||||
ctx.InformerFactory.Core().V1().Nodes(),
|
||||
ctx.InformerFactory.Core().V1().PersistentVolumeClaims(),
|
||||
|
|
|
@ -136,7 +136,6 @@ go_library(
|
|||
"//staging/src/k8s.io/client-go/util/keyutil:go_default_library",
|
||||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/cli/flag:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library",
|
||||
"//staging/src/k8s.io/kubelet/config/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/node-api/pkg/client/clientset/versioned:go_default_library",
|
||||
"//vendor/github.com/coreos/go-systemd/daemon:go_default_library",
|
||||
|
|
|
@ -57,7 +57,6 @@ import (
|
|||
"k8s.io/client-go/util/keyutil"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
cliflag "k8s.io/component-base/cli/flag"
|
||||
csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned"
|
||||
kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1"
|
||||
"k8s.io/kubernetes/cmd/kubelet/app/options"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
|
@ -400,7 +399,6 @@ func UnsecuredDependencies(s *options.KubeletServer) (*kubelet.Dependencies, err
|
|||
DockerClientConfig: dockerClientConfig,
|
||||
KubeClient: nil,
|
||||
HeartbeatClient: nil,
|
||||
CSIClient: nil,
|
||||
EventClient: nil,
|
||||
Mounter: mounter,
|
||||
Subpather: subpather,
|
||||
|
@ -598,10 +596,6 @@ func run(s *options.KubeletServer, kubeDeps *kubelet.Dependencies, stopCh <-chan
|
|||
// CRDs are JSON only, and client renegotiation for streaming is not correct as per #67803
|
||||
crdClientConfig := restclient.CopyConfig(clientConfig)
|
||||
crdClientConfig.ContentType = "application/json"
|
||||
kubeDeps.CSIClient, err = csiclientset.NewForConfig(crdClientConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize kubelet storage client: %v", err)
|
||||
}
|
||||
|
||||
kubeDeps.NodeAPIClient, err = nodeapiclientset.NewForConfig(crdClientConfig)
|
||||
if err != nil {
|
||||
|
|
|
@ -107,9 +107,9 @@ test/e2e/testing-manifests/rbd-storage-class.yaml,storageclasses,,slow,v1beta1,v
|
|||
)
|
||||
|
||||
KUBE_OLD_API_VERSION="networking.k8s.io/v1,storage.k8s.io/v1beta1,extensions/v1beta1"
|
||||
KUBE_NEW_API_VERSION="networking.k8s.io/v1,storage.k8s.io/v1,extensions/v1beta1,policy/v1beta1"
|
||||
KUBE_NEW_API_VERSION="networking.k8s.io/v1,storage.k8s.io/v1beta1,storage.k8s.io/v1,extensions/v1beta1,policy/v1beta1"
|
||||
KUBE_OLD_STORAGE_VERSIONS="storage.k8s.io/v1beta1"
|
||||
KUBE_NEW_STORAGE_VERSIONS="storage.k8s.io/v1"
|
||||
KUBE_NEW_STORAGE_VERSIONS="storage.k8s.io/v1beta1,storage.k8s.io/v1"
|
||||
|
||||
### END TEST DEFINITION CUSTOMIZATION ###
|
||||
|
||||
|
|
|
@ -142,6 +142,8 @@ func TestDefaulting(t *testing.T) {
|
|||
{Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicyList"}: {},
|
||||
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "StorageClass"}: {},
|
||||
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "StorageClassList"}: {},
|
||||
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSIDriver"}: {},
|
||||
{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSIDriverList"}: {},
|
||||
{Group: "storage.k8s.io", Version: "v1", Kind: "StorageClass"}: {},
|
||||
{Group: "storage.k8s.io", Version: "v1", Kind: "StorageClassList"}: {},
|
||||
{Group: "authentication.k8s.io", Version: "v1", Kind: "TokenRequest"}: {},
|
||||
|
|
|
@ -61,8 +61,6 @@ const isInvalidQuotaResource string = `must be a standard resource for quota`
|
|||
const fieldImmutableErrorMsg string = apimachineryvalidation.FieldImmutableErrorMsg
|
||||
const isNotIntegerErrorMsg string = `must be an integer`
|
||||
const isNotPositiveErrorMsg string = `must be greater than zero`
|
||||
const csiDriverNameRexpErrMsg string = "must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character"
|
||||
const csiDriverNameRexpFmt string = `^[a-zA-Z0-9][-a-zA-Z0-9_.]{0,61}[a-zA-Z-0-9]$`
|
||||
|
||||
var pdPartitionErrorMsg string = validation.InclusiveRangeError(1, 255)
|
||||
var fileModeErrorMsg string = "must be a number between 0 and 0777 (octal), both inclusive"
|
||||
|
@ -74,8 +72,6 @@ var iscsiInitiatorIqnRegex = regexp.MustCompile(`iqn\.\d{4}-\d{2}\.([[:alnum:]-.
|
|||
var iscsiInitiatorEuiRegex = regexp.MustCompile(`^eui.[[:alnum:]]{16}$`)
|
||||
var iscsiInitiatorNaaRegex = regexp.MustCompile(`^naa.[[:alnum:]]{32}$`)
|
||||
|
||||
var csiDriverNameRexp = regexp.MustCompile(csiDriverNameRexpFmt)
|
||||
|
||||
// ValidateHasLabel requires that metav1.ObjectMeta has a Label with key and expectedValue
|
||||
func ValidateHasLabel(meta metav1.ObjectMeta, fldPath *field.Path, key, expectedValue string) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
@ -1446,9 +1442,10 @@ func ValidateCSIDriverName(driverName string, fldPath *field.Path) field.ErrorLi
|
|||
allErrs = append(allErrs, field.TooLong(fldPath, driverName, 63))
|
||||
}
|
||||
|
||||
if !csiDriverNameRexp.MatchString(driverName) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, driverName, validation.RegexError(csiDriverNameRexpErrMsg, csiDriverNameRexpFmt, "csi-hostpath")))
|
||||
for _, msg := range validation.IsDNS1123Subdomain(strings.ToLower(driverName)) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, driverName, msg))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
|
|
@ -1775,24 +1775,30 @@ func TestValidateCSIVolumeSource(t *testing.T) {
|
|||
csi: &core.CSIPersistentVolumeSource{Driver: "io-kubernetes-storage-csi-flex", VolumeHandle: "test-123"},
|
||||
},
|
||||
{
|
||||
name: "driver name: ok underscore only",
|
||||
csi: &core.CSIPersistentVolumeSource{Driver: "io_kubernetes_storage_csi_flex", VolumeHandle: "test-123"},
|
||||
name: "driver name: invalid underscore",
|
||||
csi: &core.CSIPersistentVolumeSource{Driver: "io_kubernetes_storage_csi_flex", VolumeHandle: "test-123"},
|
||||
errtype: field.ErrorTypeInvalid,
|
||||
errfield: "driver",
|
||||
},
|
||||
{
|
||||
name: "driver name: ok dot underscores",
|
||||
csi: &core.CSIPersistentVolumeSource{Driver: "io.kubernetes.storage_csi.flex", VolumeHandle: "test-123"},
|
||||
name: "driver name: invalid dot underscores",
|
||||
csi: &core.CSIPersistentVolumeSource{Driver: "io.kubernetes.storage_csi.flex", VolumeHandle: "test-123"},
|
||||
errtype: field.ErrorTypeInvalid,
|
||||
errfield: "driver",
|
||||
},
|
||||
{
|
||||
name: "driver name: ok beginnin with number",
|
||||
csi: &core.CSIPersistentVolumeSource{Driver: "2io.kubernetes.storage_csi.flex", VolumeHandle: "test-123"},
|
||||
csi: &core.CSIPersistentVolumeSource{Driver: "2io.kubernetes.storage-csi.flex", VolumeHandle: "test-123"},
|
||||
},
|
||||
{
|
||||
name: "driver name: ok ending with number",
|
||||
csi: &core.CSIPersistentVolumeSource{Driver: "io.kubernetes.storage_csi.flex2", VolumeHandle: "test-123"},
|
||||
csi: &core.CSIPersistentVolumeSource{Driver: "io.kubernetes.storage-csi.flex2", VolumeHandle: "test-123"},
|
||||
},
|
||||
{
|
||||
name: "driver name: ok dot dash underscores",
|
||||
csi: &core.CSIPersistentVolumeSource{Driver: "io.kubernetes-storage.csi_flex", VolumeHandle: "test-123"},
|
||||
name: "driver name: invalid dot dash underscores",
|
||||
csi: &core.CSIPersistentVolumeSource{Driver: "io.kubernetes-storage.csi_flex", VolumeHandle: "test-123"},
|
||||
errtype: field.ErrorTypeInvalid,
|
||||
errfield: "driver",
|
||||
},
|
||||
{
|
||||
name: "driver name: invalid length 0",
|
||||
|
@ -1801,10 +1807,8 @@ func TestValidateCSIVolumeSource(t *testing.T) {
|
|||
errfield: "driver",
|
||||
},
|
||||
{
|
||||
name: "driver name: invalid length 1",
|
||||
csi: &core.CSIPersistentVolumeSource{Driver: "a", VolumeHandle: "test-123"},
|
||||
errtype: field.ErrorTypeInvalid,
|
||||
errfield: "driver",
|
||||
name: "driver name: ok length 1",
|
||||
csi: &core.CSIPersistentVolumeSource{Driver: "a", VolumeHandle: "test-123"},
|
||||
},
|
||||
{
|
||||
name: "driver name: invalid length > 63",
|
||||
|
|
|
@ -34,5 +34,18 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||
bindingModes := []storage.VolumeBindingMode{storage.VolumeBindingImmediate, storage.VolumeBindingWaitForFirstConsumer}
|
||||
obj.VolumeBindingMode = &bindingModes[c.Rand.Intn(len(bindingModes))]
|
||||
},
|
||||
func(obj *storage.CSIDriver, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(obj) // fuzz self without calling this function again
|
||||
|
||||
// match defaulting
|
||||
if obj.Spec.AttachRequired == nil {
|
||||
obj.Spec.AttachRequired = new(bool)
|
||||
*(obj.Spec.AttachRequired) = true
|
||||
}
|
||||
if obj.Spec.PodInfoOnMount == nil {
|
||||
obj.Spec.PodInfoOnMount = new(bool)
|
||||
*(obj.Spec.PodInfoOnMount) = false
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,10 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
|||
&StorageClassList{},
|
||||
&VolumeAttachment{},
|
||||
&VolumeAttachmentList{},
|
||||
&CSINode{},
|
||||
&CSINodeList{},
|
||||
&CSIDriver{},
|
||||
&CSIDriverList{},
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -215,3 +215,160 @@ const (
|
|||
// binding will occur during Pod scheduing.
|
||||
VolumeBindingWaitForFirstConsumer VolumeBindingMode = "WaitForFirstConsumer"
|
||||
)
|
||||
|
||||
// +genclient
|
||||
// +genclient:nonNamespaced
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// CSIDriver captures information about a Container Storage Interface (CSI)
|
||||
// volume driver deployed on the cluster.
|
||||
// CSI drivers do not need to create the CSIDriver object directly. Instead they may use the
|
||||
// cluster-driver-registrar sidecar container. When deployed with a CSI driver it automatically
|
||||
// creates a CSIDriver object representing the driver.
|
||||
// Kubernetes attach detach controller uses this object to determine whether attach is required.
|
||||
// Kubelet uses this object to determine whether pod information needs to be passed on mount.
|
||||
// CSIDriver objects are non-namespaced.
|
||||
type CSIDriver struct {
|
||||
metav1.TypeMeta
|
||||
|
||||
// Standard object metadata.
|
||||
// metadata.Name indicates the name of the CSI driver that this object
|
||||
// refers to; it MUST be the same name returned by the CSI GetPluginName()
|
||||
// call for that driver.
|
||||
// The driver name must be 63 characters or less, beginning and ending with
|
||||
// an alphanumeric character ([a-z0-9A-Z]) with dashes (-), dots (.), and
|
||||
// alphanumerics between.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
|
||||
metav1.ObjectMeta
|
||||
|
||||
// Specification of the CSI Driver.
|
||||
Spec CSIDriverSpec
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// CSIDriverList is a collection of CSIDriver objects.
|
||||
type CSIDriverList struct {
|
||||
metav1.TypeMeta
|
||||
|
||||
// Standard list metadata
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
|
||||
// +optional
|
||||
metav1.ListMeta
|
||||
|
||||
// items is the list of CSIDriver
|
||||
Items []CSIDriver
|
||||
}
|
||||
|
||||
// CSIDriverSpec is the specification of a CSIDriver.
|
||||
type CSIDriverSpec struct {
|
||||
// attachRequired indicates this CSI volume driver requires an attach
|
||||
// operation (because it implements the CSI ControllerPublishVolume()
|
||||
// method), and that the Kubernetes attach detach controller should call
|
||||
// the attach volume interface which checks the volumeattachment status
|
||||
// and waits until the volume is attached before proceeding to mounting.
|
||||
// The CSI external-attacher coordinates with CSI volume driver and updates
|
||||
// the volumeattachment status when the attach operation is complete.
|
||||
// If the CSIDriverRegistry feature gate is enabled and the value is
|
||||
// specified to false, the attach operation will be skipped.
|
||||
// Otherwise the attach operation will be called.
|
||||
// +optional
|
||||
AttachRequired *bool
|
||||
|
||||
// If set to true, podInfoOnMount indicates this CSI volume driver
|
||||
// requires additional pod information (like podName, podUID, etc.) during
|
||||
// mount operations.
|
||||
// If set to false, pod information will not be passed on mount.
|
||||
// Default is false.
|
||||
// The CSI driver specifies podInfoOnMount as part of driver deployment.
|
||||
// If true, Kubelet will pass pod information as VolumeContext in the CSI
|
||||
// NodePublishVolume() calls.
|
||||
// The CSI driver is responsible for parsing and validating the information
|
||||
// passed in as VolumeContext.
|
||||
// The following VolumeConext will be passed if podInfoOnMount is set to true.
|
||||
// This list might grow, but the prefix will be used.
|
||||
// "csi.storage.k8s.io/pod.name": pod.Name
|
||||
// "csi.storage.k8s.io/pod.namespace": pod.Namespace
|
||||
// "csi.storage.k8s.io/pod.uid": string(pod.UID)
|
||||
// +optional
|
||||
PodInfoOnMount *bool
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:nonNamespaced
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// CSINode holds information about all CSI drivers installed on a node.
|
||||
// CSI drivers do not need to create the CSINode object directly. As long as
|
||||
// they use the node-driver-registrar sidecar container, the kubelet will
|
||||
// automatically populate the CSINode object for the CSI driver as part of
|
||||
// kubelet plugin registration.
|
||||
// CSINode has the same name as a node. If the object is missing, it means either
|
||||
// there are no CSI Drivers available on the node, or the Kubelet version is low
|
||||
// enough that it doesn't create this object.
|
||||
// CSINode has an OwnerReference that points to the corresponding node object.
|
||||
type CSINode struct {
|
||||
metav1.TypeMeta
|
||||
|
||||
// metadata.name must be the Kubernetes node name.
|
||||
metav1.ObjectMeta
|
||||
|
||||
// spec is the specification of CSINode
|
||||
Spec CSINodeSpec
|
||||
}
|
||||
|
||||
// CSINodeSpec holds information about the specification of all CSI drivers installed on a node
|
||||
type CSINodeSpec struct {
|
||||
// drivers is a list of information of all CSI Drivers existing on a node.
|
||||
// If all drivers in the list are uninstalled, this can become empty.
|
||||
// +patchMergeKey=name
|
||||
// +patchStrategy=merge
|
||||
Drivers []CSINodeDriver
|
||||
}
|
||||
|
||||
// CSINodeDriver holds information about the specification of one CSI driver installed on a node
|
||||
type CSINodeDriver struct {
|
||||
// This is the name of the CSI driver that this object refers to.
|
||||
// This MUST be the same name returned by the CSI GetPluginName() call for
|
||||
// that driver.
|
||||
Name string
|
||||
|
||||
// nodeID of the node from the driver point of view.
|
||||
// This field enables Kubernetes to communicate with storage systems that do
|
||||
// not share the same nomenclature for nodes. For example, Kubernetes may
|
||||
// refer to a given node as "node1", but the storage system may refer to
|
||||
// the same node as "nodeA". When Kubernetes issues a command to the storage
|
||||
// system to attach a volume to a specific node, it can use this field to
|
||||
// refer to the node name using the ID that the storage system will
|
||||
// understand, e.g. "nodeA" instead of "node1". This field is required.
|
||||
NodeID string
|
||||
|
||||
// topologyKeys is the list of keys supported by the driver.
|
||||
// When a driver is initialized on a cluster, it provides a set of topology
|
||||
// keys that it understands (e.g. "company.com/zone", "company.com/region").
|
||||
// When a driver is initialized on a node, it provides the same topology keys
|
||||
// along with values. Kubelet will expose these topology keys as labels
|
||||
// on its own node object.
|
||||
// When Kubernetes does topology aware provisioning, it can use this list to
|
||||
// determine which labels it should retrieve from the node object and pass
|
||||
// back to the driver.
|
||||
// It is possible for different nodes to use different topology keys.
|
||||
// This can be empty if driver does not support topology.
|
||||
// +optional
|
||||
TopologyKeys []string
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// CSINodeList is a collection of CSINode objects.
|
||||
type CSINodeList struct {
|
||||
metav1.TypeMeta
|
||||
|
||||
// Standard list metadata
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
|
||||
// +optional
|
||||
metav1.ListMeta
|
||||
|
||||
// items is the list of CSINode
|
||||
Items []CSINode
|
||||
}
|
||||
|
|
|
@ -37,3 +37,14 @@ func SetDefaults_StorageClass(obj *storagev1beta1.StorageClass) {
|
|||
*obj.VolumeBindingMode = storagev1beta1.VolumeBindingImmediate
|
||||
}
|
||||
}
|
||||
|
||||
func SetDefaults_CSIDriver(obj *storagev1beta1.CSIDriver) {
|
||||
if obj.Spec.AttachRequired == nil {
|
||||
obj.Spec.AttachRequired = new(bool)
|
||||
*(obj.Spec.AttachRequired) = true
|
||||
}
|
||||
if obj.Spec.PodInfoOnMount == nil {
|
||||
obj.Spec.PodInfoOnMount = new(bool)
|
||||
*(obj.Spec.PodInfoOnMount) = false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,3 +60,24 @@ func TestSetDefaultVolumeBindingMode(t *testing.T) {
|
|||
t.Errorf("Expected VolumeBindingMode to be defaulted to: %+v, got: %+v", defaultMode, outMode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDefaultAttachRequired(t *testing.T) {
|
||||
driver := &storagev1beta1.CSIDriver{}
|
||||
|
||||
// field should be defaulted
|
||||
defaultAttach := true
|
||||
defaultPodInfo := false
|
||||
output := roundTrip(t, runtime.Object(driver)).(*storagev1beta1.CSIDriver)
|
||||
outAttach := output.Spec.AttachRequired
|
||||
if outAttach == nil {
|
||||
t.Errorf("Expected AttachRequired to be defaulted to: %+v, got: nil", defaultAttach)
|
||||
} else if *outAttach != defaultAttach {
|
||||
t.Errorf("Expected AttachRequired to be defaulted to: %+v, got: %+v", defaultAttach, outAttach)
|
||||
}
|
||||
outPodInfo := output.Spec.PodInfoOnMount
|
||||
if outPodInfo == nil {
|
||||
t.Errorf("Expected PodInfoOnMount to be defaulted to: %+v, got: nil", defaultPodInfo)
|
||||
} else if *outPodInfo != defaultPodInfo {
|
||||
t.Errorf("Expected PodInfoOnMount to be defaulted to: %+v, got: %+v", defaultPodInfo, outPodInfo)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,76 @@ func init() {
|
|||
// RegisterConversions adds conversion functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterConversions(s *runtime.Scheme) error {
|
||||
if err := s.AddGeneratedConversionFunc((*v1beta1.CSIDriver)(nil), (*storage.CSIDriver)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1beta1_CSIDriver_To_storage_CSIDriver(a.(*v1beta1.CSIDriver), b.(*storage.CSIDriver), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*storage.CSIDriver)(nil), (*v1beta1.CSIDriver)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_storage_CSIDriver_To_v1beta1_CSIDriver(a.(*storage.CSIDriver), b.(*v1beta1.CSIDriver), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1beta1.CSIDriverList)(nil), (*storage.CSIDriverList)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1beta1_CSIDriverList_To_storage_CSIDriverList(a.(*v1beta1.CSIDriverList), b.(*storage.CSIDriverList), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*storage.CSIDriverList)(nil), (*v1beta1.CSIDriverList)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_storage_CSIDriverList_To_v1beta1_CSIDriverList(a.(*storage.CSIDriverList), b.(*v1beta1.CSIDriverList), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1beta1.CSIDriverSpec)(nil), (*storage.CSIDriverSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec(a.(*v1beta1.CSIDriverSpec), b.(*storage.CSIDriverSpec), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*storage.CSIDriverSpec)(nil), (*v1beta1.CSIDriverSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec(a.(*storage.CSIDriverSpec), b.(*v1beta1.CSIDriverSpec), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1beta1.CSINode)(nil), (*storage.CSINode)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1beta1_CSINode_To_storage_CSINode(a.(*v1beta1.CSINode), b.(*storage.CSINode), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*storage.CSINode)(nil), (*v1beta1.CSINode)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_storage_CSINode_To_v1beta1_CSINode(a.(*storage.CSINode), b.(*v1beta1.CSINode), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1beta1.CSINodeDriver)(nil), (*storage.CSINodeDriver)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1beta1_CSINodeDriver_To_storage_CSINodeDriver(a.(*v1beta1.CSINodeDriver), b.(*storage.CSINodeDriver), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*storage.CSINodeDriver)(nil), (*v1beta1.CSINodeDriver)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_storage_CSINodeDriver_To_v1beta1_CSINodeDriver(a.(*storage.CSINodeDriver), b.(*v1beta1.CSINodeDriver), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1beta1.CSINodeList)(nil), (*storage.CSINodeList)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1beta1_CSINodeList_To_storage_CSINodeList(a.(*v1beta1.CSINodeList), b.(*storage.CSINodeList), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*storage.CSINodeList)(nil), (*v1beta1.CSINodeList)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_storage_CSINodeList_To_v1beta1_CSINodeList(a.(*storage.CSINodeList), b.(*v1beta1.CSINodeList), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1beta1.CSINodeSpec)(nil), (*storage.CSINodeSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1beta1_CSINodeSpec_To_storage_CSINodeSpec(a.(*v1beta1.CSINodeSpec), b.(*storage.CSINodeSpec), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*storage.CSINodeSpec)(nil), (*v1beta1.CSINodeSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_storage_CSINodeSpec_To_v1beta1_CSINodeSpec(a.(*storage.CSINodeSpec), b.(*v1beta1.CSINodeSpec), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1beta1.StorageClass)(nil), (*storage.StorageClass)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1beta1_StorageClass_To_storage_StorageClass(a.(*v1beta1.StorageClass), b.(*storage.StorageClass), scope)
|
||||
}); err != nil {
|
||||
|
@ -121,6 +191,168 @@ func RegisterConversions(s *runtime.Scheme) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_CSIDriver_To_storage_CSIDriver(in *v1beta1.CSIDriver, out *storage.CSIDriver, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
if err := Convert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_CSIDriver_To_storage_CSIDriver is an autogenerated conversion function.
|
||||
func Convert_v1beta1_CSIDriver_To_storage_CSIDriver(in *v1beta1.CSIDriver, out *storage.CSIDriver, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_CSIDriver_To_storage_CSIDriver(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_storage_CSIDriver_To_v1beta1_CSIDriver(in *storage.CSIDriver, out *v1beta1.CSIDriver, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
if err := Convert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_storage_CSIDriver_To_v1beta1_CSIDriver is an autogenerated conversion function.
|
||||
func Convert_storage_CSIDriver_To_v1beta1_CSIDriver(in *storage.CSIDriver, out *v1beta1.CSIDriver, s conversion.Scope) error {
|
||||
return autoConvert_storage_CSIDriver_To_v1beta1_CSIDriver(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_CSIDriverList_To_storage_CSIDriverList(in *v1beta1.CSIDriverList, out *storage.CSIDriverList, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
out.Items = *(*[]storage.CSIDriver)(unsafe.Pointer(&in.Items))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_CSIDriverList_To_storage_CSIDriverList is an autogenerated conversion function.
|
||||
func Convert_v1beta1_CSIDriverList_To_storage_CSIDriverList(in *v1beta1.CSIDriverList, out *storage.CSIDriverList, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_CSIDriverList_To_storage_CSIDriverList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_storage_CSIDriverList_To_v1beta1_CSIDriverList(in *storage.CSIDriverList, out *v1beta1.CSIDriverList, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
out.Items = *(*[]v1beta1.CSIDriver)(unsafe.Pointer(&in.Items))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_storage_CSIDriverList_To_v1beta1_CSIDriverList is an autogenerated conversion function.
|
||||
func Convert_storage_CSIDriverList_To_v1beta1_CSIDriverList(in *storage.CSIDriverList, out *v1beta1.CSIDriverList, s conversion.Scope) error {
|
||||
return autoConvert_storage_CSIDriverList_To_v1beta1_CSIDriverList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec(in *v1beta1.CSIDriverSpec, out *storage.CSIDriverSpec, s conversion.Scope) error {
|
||||
out.AttachRequired = (*bool)(unsafe.Pointer(in.AttachRequired))
|
||||
out.PodInfoOnMount = (*bool)(unsafe.Pointer(in.PodInfoOnMount))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec is an autogenerated conversion function.
|
||||
func Convert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec(in *v1beta1.CSIDriverSpec, out *storage.CSIDriverSpec, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec(in *storage.CSIDriverSpec, out *v1beta1.CSIDriverSpec, s conversion.Scope) error {
|
||||
out.AttachRequired = (*bool)(unsafe.Pointer(in.AttachRequired))
|
||||
out.PodInfoOnMount = (*bool)(unsafe.Pointer(in.PodInfoOnMount))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec is an autogenerated conversion function.
|
||||
func Convert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec(in *storage.CSIDriverSpec, out *v1beta1.CSIDriverSpec, s conversion.Scope) error {
|
||||
return autoConvert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_CSINode_To_storage_CSINode(in *v1beta1.CSINode, out *storage.CSINode, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
if err := Convert_v1beta1_CSINodeSpec_To_storage_CSINodeSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_CSINode_To_storage_CSINode is an autogenerated conversion function.
|
||||
func Convert_v1beta1_CSINode_To_storage_CSINode(in *v1beta1.CSINode, out *storage.CSINode, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_CSINode_To_storage_CSINode(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_storage_CSINode_To_v1beta1_CSINode(in *storage.CSINode, out *v1beta1.CSINode, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
if err := Convert_storage_CSINodeSpec_To_v1beta1_CSINodeSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_storage_CSINode_To_v1beta1_CSINode is an autogenerated conversion function.
|
||||
func Convert_storage_CSINode_To_v1beta1_CSINode(in *storage.CSINode, out *v1beta1.CSINode, s conversion.Scope) error {
|
||||
return autoConvert_storage_CSINode_To_v1beta1_CSINode(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_CSINodeDriver_To_storage_CSINodeDriver(in *v1beta1.CSINodeDriver, out *storage.CSINodeDriver, s conversion.Scope) error {
|
||||
out.Name = in.Name
|
||||
out.NodeID = in.NodeID
|
||||
out.TopologyKeys = *(*[]string)(unsafe.Pointer(&in.TopologyKeys))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_CSINodeDriver_To_storage_CSINodeDriver is an autogenerated conversion function.
|
||||
func Convert_v1beta1_CSINodeDriver_To_storage_CSINodeDriver(in *v1beta1.CSINodeDriver, out *storage.CSINodeDriver, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_CSINodeDriver_To_storage_CSINodeDriver(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_storage_CSINodeDriver_To_v1beta1_CSINodeDriver(in *storage.CSINodeDriver, out *v1beta1.CSINodeDriver, s conversion.Scope) error {
|
||||
out.Name = in.Name
|
||||
out.NodeID = in.NodeID
|
||||
out.TopologyKeys = *(*[]string)(unsafe.Pointer(&in.TopologyKeys))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_storage_CSINodeDriver_To_v1beta1_CSINodeDriver is an autogenerated conversion function.
|
||||
func Convert_storage_CSINodeDriver_To_v1beta1_CSINodeDriver(in *storage.CSINodeDriver, out *v1beta1.CSINodeDriver, s conversion.Scope) error {
|
||||
return autoConvert_storage_CSINodeDriver_To_v1beta1_CSINodeDriver(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_CSINodeList_To_storage_CSINodeList(in *v1beta1.CSINodeList, out *storage.CSINodeList, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
out.Items = *(*[]storage.CSINode)(unsafe.Pointer(&in.Items))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_CSINodeList_To_storage_CSINodeList is an autogenerated conversion function.
|
||||
func Convert_v1beta1_CSINodeList_To_storage_CSINodeList(in *v1beta1.CSINodeList, out *storage.CSINodeList, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_CSINodeList_To_storage_CSINodeList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_storage_CSINodeList_To_v1beta1_CSINodeList(in *storage.CSINodeList, out *v1beta1.CSINodeList, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
out.Items = *(*[]v1beta1.CSINode)(unsafe.Pointer(&in.Items))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_storage_CSINodeList_To_v1beta1_CSINodeList is an autogenerated conversion function.
|
||||
func Convert_storage_CSINodeList_To_v1beta1_CSINodeList(in *storage.CSINodeList, out *v1beta1.CSINodeList, s conversion.Scope) error {
|
||||
return autoConvert_storage_CSINodeList_To_v1beta1_CSINodeList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_CSINodeSpec_To_storage_CSINodeSpec(in *v1beta1.CSINodeSpec, out *storage.CSINodeSpec, s conversion.Scope) error {
|
||||
out.Drivers = *(*[]storage.CSINodeDriver)(unsafe.Pointer(&in.Drivers))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_CSINodeSpec_To_storage_CSINodeSpec is an autogenerated conversion function.
|
||||
func Convert_v1beta1_CSINodeSpec_To_storage_CSINodeSpec(in *v1beta1.CSINodeSpec, out *storage.CSINodeSpec, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_CSINodeSpec_To_storage_CSINodeSpec(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_storage_CSINodeSpec_To_v1beta1_CSINodeSpec(in *storage.CSINodeSpec, out *v1beta1.CSINodeSpec, s conversion.Scope) error {
|
||||
out.Drivers = *(*[]v1beta1.CSINodeDriver)(unsafe.Pointer(&in.Drivers))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_storage_CSINodeSpec_To_v1beta1_CSINodeSpec is an autogenerated conversion function.
|
||||
func Convert_storage_CSINodeSpec_To_v1beta1_CSINodeSpec(in *storage.CSINodeSpec, out *v1beta1.CSINodeSpec, s conversion.Scope) error {
|
||||
return autoConvert_storage_CSINodeSpec_To_v1beta1_CSINodeSpec(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_StorageClass_To_storage_StorageClass(in *v1beta1.StorageClass, out *storage.StorageClass, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
out.Provisioner = in.Provisioner
|
||||
|
|
|
@ -29,11 +29,24 @@ import (
|
|||
// Public to allow building arbitrary schemes.
|
||||
// All generated defaulters are covering - they call all nested defaulters.
|
||||
func RegisterDefaults(scheme *runtime.Scheme) error {
|
||||
scheme.AddTypeDefaultingFunc(&v1beta1.CSIDriver{}, func(obj interface{}) { SetObjectDefaults_CSIDriver(obj.(*v1beta1.CSIDriver)) })
|
||||
scheme.AddTypeDefaultingFunc(&v1beta1.CSIDriverList{}, func(obj interface{}) { SetObjectDefaults_CSIDriverList(obj.(*v1beta1.CSIDriverList)) })
|
||||
scheme.AddTypeDefaultingFunc(&v1beta1.StorageClass{}, func(obj interface{}) { SetObjectDefaults_StorageClass(obj.(*v1beta1.StorageClass)) })
|
||||
scheme.AddTypeDefaultingFunc(&v1beta1.StorageClassList{}, func(obj interface{}) { SetObjectDefaults_StorageClassList(obj.(*v1beta1.StorageClassList)) })
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetObjectDefaults_CSIDriver(in *v1beta1.CSIDriver) {
|
||||
SetDefaults_CSIDriver(in)
|
||||
}
|
||||
|
||||
func SetObjectDefaults_CSIDriverList(in *v1beta1.CSIDriverList) {
|
||||
for i := range in.Items {
|
||||
a := &in.Items[i]
|
||||
SetObjectDefaults_CSIDriver(a)
|
||||
}
|
||||
}
|
||||
|
||||
func SetObjectDefaults_StorageClass(in *v1beta1.StorageClass) {
|
||||
SetDefaults_StorageClass(in)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
|
@ -36,6 +37,8 @@ const (
|
|||
|
||||
maxAttachedVolumeMetadataSize = 256 * (1 << 10) // 256 kB
|
||||
maxVolumeErrorMessageSize = 1024
|
||||
|
||||
csiNodeIDMaxLength = 128
|
||||
)
|
||||
|
||||
// ValidateStorageClass validates a StorageClass.
|
||||
|
@ -266,3 +269,144 @@ func validateAllowedTopologies(topologies []api.TopologySelectorTerm, fldPath *f
|
|||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateCSINode validates a CSINode.
|
||||
func ValidateCSINode(csiNode *storage.CSINode) field.ErrorList {
|
||||
allErrs := apivalidation.ValidateObjectMeta(&csiNode.ObjectMeta, false, apivalidation.ValidateNodeName, field.NewPath("metadata"))
|
||||
allErrs = append(allErrs, validateCSINodeSpec(&csiNode.Spec, field.NewPath("spec"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateCSINodeUpdate validates a CSINode.
|
||||
func ValidateCSINodeUpdate(new, old *storage.CSINode) field.ErrorList {
|
||||
allErrs := ValidateCSINode(new)
|
||||
|
||||
// Validate modifying fields inside an existing CSINodeDriver entry is not allowed
|
||||
for _, oldDriver := range old.Spec.Drivers {
|
||||
for _, newDriver := range new.Spec.Drivers {
|
||||
if oldDriver.Name == newDriver.Name {
|
||||
if !apiequality.Semantic.DeepEqual(oldDriver, newDriver) {
|
||||
allErrs = append(allErrs, field.Invalid(field.NewPath("CSINodeDriver"), newDriver, "field is immutable"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateCSINodeSpec tests that the specified CSINodeSpec has valid data.
|
||||
func validateCSINodeSpec(
|
||||
spec *storage.CSINodeSpec, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, validateCSINodeDrivers(spec.Drivers, fldPath.Child("drivers"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateCSINodeDrivers tests that the specified CSINodeDrivers have valid data.
|
||||
func validateCSINodeDrivers(drivers []storage.CSINodeDriver, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
driverNamesInSpecs := make(sets.String)
|
||||
for i, driver := range drivers {
|
||||
idxPath := fldPath.Index(i)
|
||||
allErrs = append(allErrs, validateCSINodeDriver(driver, driverNamesInSpecs, idxPath)...)
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validateCSINodeDriverNodeID tests if Name in CSINodeDriver is a valid node id.
|
||||
func validateCSINodeDriverNodeID(nodeID string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
// nodeID is always required
|
||||
if len(nodeID) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath, nodeID))
|
||||
}
|
||||
if len(nodeID) > csiNodeIDMaxLength {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, nodeID, fmt.Sprintf("must be %d characters or less", csiNodeIDMaxLength)))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validateCSINodeDriver tests if CSINodeDriver has valid entries
|
||||
func validateCSINodeDriver(driver storage.CSINodeDriver, driverNamesInSpecs sets.String, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
allErrs = append(allErrs, apivalidation.ValidateCSIDriverName(driver.Name, fldPath.Child("name"))...)
|
||||
allErrs = append(allErrs, validateCSINodeDriverNodeID(driver.NodeID, fldPath.Child("nodeID"))...)
|
||||
|
||||
// check for duplicate entries for the same driver in specs
|
||||
if driverNamesInSpecs.Has(driver.Name) {
|
||||
allErrs = append(allErrs, field.Duplicate(fldPath.Child("name"), driver.Name))
|
||||
}
|
||||
driverNamesInSpecs.Insert(driver.Name)
|
||||
topoKeys := make(sets.String)
|
||||
for _, key := range driver.TopologyKeys {
|
||||
if len(key) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath, key))
|
||||
}
|
||||
|
||||
if topoKeys.Has(key) {
|
||||
allErrs = append(allErrs, field.Duplicate(fldPath, key))
|
||||
}
|
||||
topoKeys.Insert(key)
|
||||
|
||||
for _, msg := range validation.IsQualifiedName(key) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, driver.TopologyKeys, msg))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateCSIDriver validates a CSIDriver.
|
||||
func ValidateCSIDriver(csiDriver *storage.CSIDriver) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, apivalidation.ValidateCSIDriverName(csiDriver.Name, field.NewPath("name"))...)
|
||||
|
||||
allErrs = append(allErrs, validateCSIDriverSpec(&csiDriver.Spec, field.NewPath("spec"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateCSIDriverUpdate validates a CSIDriver.
|
||||
func ValidateCSIDriverUpdate(new, old *storage.CSIDriver) field.ErrorList {
|
||||
allErrs := ValidateCSIDriver(new)
|
||||
|
||||
// Spec is read-only
|
||||
// If this ever relaxes in the future, make sure to increment the Generation number in PrepareForUpdate
|
||||
if !apiequality.Semantic.DeepEqual(old.Spec, new.Spec) {
|
||||
allErrs = append(allErrs, field.Invalid(field.NewPath("spec"), new.Spec, "field is immutable"))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateCSIDriverSpec tests that the specified CSIDriverSpec
|
||||
// has valid data.
|
||||
func validateCSIDriverSpec(
|
||||
spec *storage.CSIDriverSpec, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, validateAttachRequired(spec.AttachRequired, fldPath.Child("attachedRequired"))...)
|
||||
allErrs = append(allErrs, validatePodInfoOnMount(spec.PodInfoOnMount, fldPath.Child("podInfoOnMount"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validateAttachRequired tests if attachRequired is set for CSIDriver.
|
||||
func validateAttachRequired(attachRequired *bool, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if attachRequired == nil {
|
||||
allErrs = append(allErrs, field.Required(fldPath, ""))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validatePodInfoOnMount tests if podInfoOnMount is set for CSIDriver.
|
||||
func validatePodInfoOnMount(podInfoOnMount *bool, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if podInfoOnMount == nil {
|
||||
allErrs = append(allErrs, field.Required(fldPath, ""))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
|
|
@ -870,3 +870,628 @@ func TestValidateAllowedTopologies(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSINodeValidation(t *testing.T) {
|
||||
driverName := "driver-name"
|
||||
driverName2 := "1io.kubernetes-storage-2-csi-driver3"
|
||||
longName := "my-a-b-c-d-c-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z-ABCDEFGHIJKLMNOPQRSTUVWXYZ-driver"
|
||||
nodeID := "nodeA"
|
||||
successCases := []storage.CSINode{
|
||||
{
|
||||
// driver name: dot only
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// driver name: dash only
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo2"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "io-kubernetes-storage-csi-driver",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// driver name: numbers
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo3"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "1io-kubernetes-storage-2-csi-driver3",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// driver name: dot, dash
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo4"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "io.kubernetes.storage-csi-driver",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// driver name: dot, dash, and numbers
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo5"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: driverName2,
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Driver name length 1
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo2"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "a",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// multiple drivers with different node IDs, topology keys
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo6"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "driver1",
|
||||
NodeID: "node1",
|
||||
TopologyKeys: []string{"key1", "key2"},
|
||||
},
|
||||
{
|
||||
Name: "driverB",
|
||||
NodeID: "nodeA",
|
||||
TopologyKeys: []string{"keyA", "keyB"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// multiple drivers with same node IDs, topology keys
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo7"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "driver1",
|
||||
NodeID: "node1",
|
||||
TopologyKeys: []string{"key1"},
|
||||
},
|
||||
{
|
||||
Name: "driver2",
|
||||
NodeID: "node1",
|
||||
TopologyKeys: []string{"key1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// topology key names with -, _, and dot .
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo8"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "driver1",
|
||||
NodeID: "node1",
|
||||
TopologyKeys: []string{"zone_1", "zone.2"},
|
||||
},
|
||||
{
|
||||
Name: "driver2",
|
||||
NodeID: "node1",
|
||||
TopologyKeys: []string{"zone-3", "zone.4"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// topology prefix with - and dot.
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo9"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "driver1",
|
||||
NodeID: "node1",
|
||||
TopologyKeys: []string{"company-com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// No topology keys
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo10"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: driverName,
|
||||
NodeID: nodeID,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, csiNode := range successCases {
|
||||
if errs := ValidateCSINode(&csiNode); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
}
|
||||
errorCases := []storage.CSINode{
|
||||
{
|
||||
// Empty driver name
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Invalid start char in driver name
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo3"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "_io.kubernetes.storage.csi.driver",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Invalid end char in driver name
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo4"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver/",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Invalid separators in driver name
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo5"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "io/kubernetes/storage/csi~driver",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// driver name: underscore only
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo6"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "io_kubernetes_storage_csi_driver",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Driver name length > 63
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo7"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: longName,
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// No driver name
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo8"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Empty individual topology key
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo9"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: driverName,
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", ""},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// duplicate drivers in driver specs
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo10"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "driver1",
|
||||
NodeID: "node1",
|
||||
TopologyKeys: []string{"key1", "key2"},
|
||||
},
|
||||
{
|
||||
Name: "driver1",
|
||||
NodeID: "nodeX",
|
||||
TopologyKeys: []string{"keyA", "keyB"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// single driver with duplicate topology keys in driver specs
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo11"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "driver1",
|
||||
NodeID: "node1",
|
||||
TopologyKeys: []string{"key1", "key1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// multiple drivers with one set of duplicate topology keys in driver specs
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo12"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "driver1",
|
||||
NodeID: "node1",
|
||||
TopologyKeys: []string{"key1"},
|
||||
},
|
||||
{
|
||||
Name: "driver2",
|
||||
NodeID: "nodeX",
|
||||
TopologyKeys: []string{"keyA", "keyA"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Empty NodeID
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo13"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: driverName,
|
||||
NodeID: "",
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// topology prefix should be lower case
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo14"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: driverName,
|
||||
NodeID: "node1",
|
||||
TopologyKeys: []string{"Company.Com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, csiNode := range errorCases {
|
||||
if errs := ValidateCSINode(&csiNode); len(errs) == 0 {
|
||||
t.Errorf("Expected failure for test: %v", csiNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSINodeUpdateValidation(t *testing.T) {
|
||||
//driverName := "driver-name"
|
||||
//driverName2 := "1io.kubernetes-storage-2-csi-driver3"
|
||||
//longName := "my-a-b-c-d-c-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z-ABCDEFGHIJKLMNOPQRSTUVWXYZ-driver"
|
||||
nodeID := "nodeA"
|
||||
|
||||
old := storage.CSINode{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver-1",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver-2",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
successCases := []storage.CSINode{
|
||||
{
|
||||
// no change
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver-1",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver-2",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// remove a driver
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver-1",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// add a driver
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver-1",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver-2",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver-3",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// remove a driver and add a driver
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver-1",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.new-driver",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, csiNode := range successCases {
|
||||
if errs := ValidateCSINodeUpdate(&csiNode, &old); len(errs) != 0 {
|
||||
t.Errorf("expected success: %+v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
errorCases := []storage.CSINode{
|
||||
{
|
||||
// invalid change node id
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver-1",
|
||||
NodeID: "nodeB",
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver-2",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// invalid change topology keys
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "foo1"},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver-1",
|
||||
NodeID: "nodeB",
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
{
|
||||
Name: "io.kubernetes.storage.csi.driver-2",
|
||||
NodeID: nodeID,
|
||||
TopologyKeys: []string{"company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, csiNode := range errorCases {
|
||||
if errs := ValidateCSINodeUpdate(&csiNode, &old); len(errs) == 0 {
|
||||
t.Errorf("Expected failure for test: %+v", csiNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSIDriverValidation(t *testing.T) {
|
||||
driverName := "test-driver"
|
||||
longName := "my-a-b-c-d-c-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z-ABCDEFGHIJKLMNOPQRSTUVWXYZ-driver"
|
||||
invalidName := "-invalid-@#$%^&*()-"
|
||||
attachRequired := true
|
||||
attachNotRequired := false
|
||||
podInfoOnMount := true
|
||||
notPodInfoOnMount := false
|
||||
successCases := []storage.CSIDriver{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: driverName},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachRequired,
|
||||
PodInfoOnMount: &podInfoOnMount,
|
||||
},
|
||||
},
|
||||
{
|
||||
// driver name: dot only
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "io.kubernetes.storage.csi.driver"},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachRequired,
|
||||
PodInfoOnMount: &podInfoOnMount,
|
||||
},
|
||||
},
|
||||
{
|
||||
// driver name: dash only
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "io-kubernetes-storage-csi-driver"},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachRequired,
|
||||
PodInfoOnMount: ¬PodInfoOnMount,
|
||||
},
|
||||
},
|
||||
{
|
||||
// driver name: numbers
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "1csi2driver3"},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachRequired,
|
||||
PodInfoOnMount: &podInfoOnMount,
|
||||
},
|
||||
},
|
||||
{
|
||||
// driver name: dot and dash
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "io.kubernetes.storage.csi-driver"},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachRequired,
|
||||
PodInfoOnMount: &podInfoOnMount,
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: driverName},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachRequired,
|
||||
PodInfoOnMount: ¬PodInfoOnMount,
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: driverName},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachRequired,
|
||||
PodInfoOnMount: &podInfoOnMount,
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: driverName},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachNotRequired,
|
||||
PodInfoOnMount: ¬PodInfoOnMount,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, csiDriver := range successCases {
|
||||
if errs := ValidateCSIDriver(&csiDriver); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
}
|
||||
errorCases := []storage.CSIDriver{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: invalidName},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachRequired,
|
||||
PodInfoOnMount: &podInfoOnMount,
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: longName},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachNotRequired,
|
||||
PodInfoOnMount: ¬PodInfoOnMount,
|
||||
},
|
||||
},
|
||||
{
|
||||
// AttachRequired not set
|
||||
ObjectMeta: metav1.ObjectMeta{Name: driverName},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: nil,
|
||||
PodInfoOnMount: &podInfoOnMount,
|
||||
},
|
||||
},
|
||||
{
|
||||
// AttachRequired not set
|
||||
ObjectMeta: metav1.ObjectMeta{Name: driverName},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachNotRequired,
|
||||
PodInfoOnMount: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, csiDriver := range errorCases {
|
||||
if errs := ValidateCSIDriver(&csiDriver); len(errs) == 0 {
|
||||
t.Errorf("Expected failure for test: %v", csiDriver)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,196 @@ import (
|
|||
core "k8s.io/kubernetes/pkg/apis/core"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSIDriver) DeepCopyInto(out *CSIDriver) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriver.
|
||||
func (in *CSIDriver) DeepCopy() *CSIDriver {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSIDriver)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CSIDriver) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSIDriverList) DeepCopyInto(out *CSIDriverList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]CSIDriver, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriverList.
|
||||
func (in *CSIDriverList) DeepCopy() *CSIDriverList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSIDriverList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CSIDriverList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSIDriverSpec) DeepCopyInto(out *CSIDriverSpec) {
|
||||
*out = *in
|
||||
if in.AttachRequired != nil {
|
||||
in, out := &in.AttachRequired, &out.AttachRequired
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.PodInfoOnMount != nil {
|
||||
in, out := &in.PodInfoOnMount, &out.PodInfoOnMount
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriverSpec.
|
||||
func (in *CSIDriverSpec) DeepCopy() *CSIDriverSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSIDriverSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSINode) DeepCopyInto(out *CSINode) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINode.
|
||||
func (in *CSINode) DeepCopy() *CSINode {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSINode)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CSINode) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSINodeDriver) DeepCopyInto(out *CSINodeDriver) {
|
||||
*out = *in
|
||||
if in.TopologyKeys != nil {
|
||||
in, out := &in.TopologyKeys, &out.TopologyKeys
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeDriver.
|
||||
func (in *CSINodeDriver) DeepCopy() *CSINodeDriver {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSINodeDriver)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSINodeList) DeepCopyInto(out *CSINodeList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]CSINode, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeList.
|
||||
func (in *CSINodeList) DeepCopy() *CSINodeList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSINodeList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CSINodeList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSINodeSpec) DeepCopyInto(out *CSINodeSpec) {
|
||||
*out = *in
|
||||
if in.Drivers != nil {
|
||||
in, out := &in.Drivers, &out.Drivers
|
||||
*out = make([]CSINodeDriver, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeSpec.
|
||||
func (in *CSINodeSpec) DeepCopy() *CSINodeSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSINodeSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StorageClass) DeepCopyInto(out *StorageClass) {
|
||||
*out = *in
|
||||
|
|
|
@ -8,6 +8,8 @@ load(
|
|||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"csidriver.go",
|
||||
"csinode.go",
|
||||
"doc.go",
|
||||
"generated_expansion.go",
|
||||
"storage_client.go",
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package internalversion
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
storage "k8s.io/kubernetes/pkg/apis/storage"
|
||||
scheme "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/scheme"
|
||||
)
|
||||
|
||||
// CSIDriversGetter has a method to return a CSIDriverInterface.
|
||||
// A group's client should implement this interface.
|
||||
type CSIDriversGetter interface {
|
||||
CSIDrivers() CSIDriverInterface
|
||||
}
|
||||
|
||||
// CSIDriverInterface has methods to work with CSIDriver resources.
|
||||
type CSIDriverInterface interface {
|
||||
Create(*storage.CSIDriver) (*storage.CSIDriver, error)
|
||||
Update(*storage.CSIDriver) (*storage.CSIDriver, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*storage.CSIDriver, error)
|
||||
List(opts v1.ListOptions) (*storage.CSIDriverList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *storage.CSIDriver, err error)
|
||||
CSIDriverExpansion
|
||||
}
|
||||
|
||||
// cSIDrivers implements CSIDriverInterface
|
||||
type cSIDrivers struct {
|
||||
client rest.Interface
|
||||
}
|
||||
|
||||
// newCSIDrivers returns a CSIDrivers
|
||||
func newCSIDrivers(c *StorageClient) *cSIDrivers {
|
||||
return &cSIDrivers{
|
||||
client: c.RESTClient(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the cSIDriver, and returns the corresponding cSIDriver object, and an error if there is any.
|
||||
func (c *cSIDrivers) Get(name string, options v1.GetOptions) (result *storage.CSIDriver, err error) {
|
||||
result = &storage.CSIDriver{}
|
||||
err = c.client.Get().
|
||||
Resource("csidrivers").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of CSIDrivers that match those selectors.
|
||||
func (c *cSIDrivers) List(opts v1.ListOptions) (result *storage.CSIDriverList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &storage.CSIDriverList{}
|
||||
err = c.client.Get().
|
||||
Resource("csidrivers").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested cSIDrivers.
|
||||
func (c *cSIDrivers) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Resource("csidrivers").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a cSIDriver and creates it. Returns the server's representation of the cSIDriver, and an error, if there is any.
|
||||
func (c *cSIDrivers) Create(cSIDriver *storage.CSIDriver) (result *storage.CSIDriver, err error) {
|
||||
result = &storage.CSIDriver{}
|
||||
err = c.client.Post().
|
||||
Resource("csidrivers").
|
||||
Body(cSIDriver).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a cSIDriver and updates it. Returns the server's representation of the cSIDriver, and an error, if there is any.
|
||||
func (c *cSIDrivers) Update(cSIDriver *storage.CSIDriver) (result *storage.CSIDriver, err error) {
|
||||
result = &storage.CSIDriver{}
|
||||
err = c.client.Put().
|
||||
Resource("csidrivers").
|
||||
Name(cSIDriver.Name).
|
||||
Body(cSIDriver).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the cSIDriver and deletes it. Returns an error if one occurs.
|
||||
func (c *cSIDrivers) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Resource("csidrivers").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *cSIDrivers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Resource("csidrivers").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched cSIDriver.
|
||||
func (c *cSIDrivers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *storage.CSIDriver, err error) {
|
||||
result = &storage.CSIDriver{}
|
||||
err = c.client.Patch(pt).
|
||||
Resource("csidrivers").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package internalversion
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
storage "k8s.io/kubernetes/pkg/apis/storage"
|
||||
scheme "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/scheme"
|
||||
)
|
||||
|
||||
// CSINodesGetter has a method to return a CSINodeInterface.
|
||||
// A group's client should implement this interface.
|
||||
type CSINodesGetter interface {
|
||||
CSINodes() CSINodeInterface
|
||||
}
|
||||
|
||||
// CSINodeInterface has methods to work with CSINode resources.
|
||||
type CSINodeInterface interface {
|
||||
Create(*storage.CSINode) (*storage.CSINode, error)
|
||||
Update(*storage.CSINode) (*storage.CSINode, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*storage.CSINode, error)
|
||||
List(opts v1.ListOptions) (*storage.CSINodeList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *storage.CSINode, err error)
|
||||
CSINodeExpansion
|
||||
}
|
||||
|
||||
// cSINodes implements CSINodeInterface
|
||||
type cSINodes struct {
|
||||
client rest.Interface
|
||||
}
|
||||
|
||||
// newCSINodes returns a CSINodes
|
||||
func newCSINodes(c *StorageClient) *cSINodes {
|
||||
return &cSINodes{
|
||||
client: c.RESTClient(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the cSINode, and returns the corresponding cSINode object, and an error if there is any.
|
||||
func (c *cSINodes) Get(name string, options v1.GetOptions) (result *storage.CSINode, err error) {
|
||||
result = &storage.CSINode{}
|
||||
err = c.client.Get().
|
||||
Resource("csinodes").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of CSINodes that match those selectors.
|
||||
func (c *cSINodes) List(opts v1.ListOptions) (result *storage.CSINodeList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &storage.CSINodeList{}
|
||||
err = c.client.Get().
|
||||
Resource("csinodes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested cSINodes.
|
||||
func (c *cSINodes) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Resource("csinodes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a cSINode and creates it. Returns the server's representation of the cSINode, and an error, if there is any.
|
||||
func (c *cSINodes) Create(cSINode *storage.CSINode) (result *storage.CSINode, err error) {
|
||||
result = &storage.CSINode{}
|
||||
err = c.client.Post().
|
||||
Resource("csinodes").
|
||||
Body(cSINode).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a cSINode and updates it. Returns the server's representation of the cSINode, and an error, if there is any.
|
||||
func (c *cSINodes) Update(cSINode *storage.CSINode) (result *storage.CSINode, err error) {
|
||||
result = &storage.CSINode{}
|
||||
err = c.client.Put().
|
||||
Resource("csinodes").
|
||||
Name(cSINode.Name).
|
||||
Body(cSINode).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the cSINode and deletes it. Returns an error if one occurs.
|
||||
func (c *cSINodes) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Resource("csinodes").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *cSINodes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Resource("csinodes").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched cSINode.
|
||||
func (c *cSINodes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *storage.CSINode, err error) {
|
||||
result = &storage.CSINode{}
|
||||
err = c.client.Patch(pt).
|
||||
Resource("csinodes").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
|
@ -9,6 +9,8 @@ go_library(
|
|||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"fake_csidriver.go",
|
||||
"fake_csinode.go",
|
||||
"fake_storage_client.go",
|
||||
"fake_storageclass.go",
|
||||
"fake_volumeattachment.go",
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
storage "k8s.io/kubernetes/pkg/apis/storage"
|
||||
)
|
||||
|
||||
// FakeCSIDrivers implements CSIDriverInterface
|
||||
type FakeCSIDrivers struct {
|
||||
Fake *FakeStorage
|
||||
}
|
||||
|
||||
var csidriversResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "", Resource: "csidrivers"}
|
||||
|
||||
var csidriversKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "", Kind: "CSIDriver"}
|
||||
|
||||
// Get takes name of the cSIDriver, and returns the corresponding cSIDriver object, and an error if there is any.
|
||||
func (c *FakeCSIDrivers) Get(name string, options v1.GetOptions) (result *storage.CSIDriver, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootGetAction(csidriversResource, name), &storage.CSIDriver{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*storage.CSIDriver), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of CSIDrivers that match those selectors.
|
||||
func (c *FakeCSIDrivers) List(opts v1.ListOptions) (result *storage.CSIDriverList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootListAction(csidriversResource, csidriversKind, opts), &storage.CSIDriverList{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &storage.CSIDriverList{ListMeta: obj.(*storage.CSIDriverList).ListMeta}
|
||||
for _, item := range obj.(*storage.CSIDriverList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested cSIDrivers.
|
||||
func (c *FakeCSIDrivers) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewRootWatchAction(csidriversResource, opts))
|
||||
}
|
||||
|
||||
// Create takes the representation of a cSIDriver and creates it. Returns the server's representation of the cSIDriver, and an error, if there is any.
|
||||
func (c *FakeCSIDrivers) Create(cSIDriver *storage.CSIDriver) (result *storage.CSIDriver, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootCreateAction(csidriversResource, cSIDriver), &storage.CSIDriver{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*storage.CSIDriver), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a cSIDriver and updates it. Returns the server's representation of the cSIDriver, and an error, if there is any.
|
||||
func (c *FakeCSIDrivers) Update(cSIDriver *storage.CSIDriver) (result *storage.CSIDriver, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootUpdateAction(csidriversResource, cSIDriver), &storage.CSIDriver{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*storage.CSIDriver), err
|
||||
}
|
||||
|
||||
// Delete takes name of the cSIDriver and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeCSIDrivers) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewRootDeleteAction(csidriversResource, name), &storage.CSIDriver{})
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeCSIDrivers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewRootDeleteCollectionAction(csidriversResource, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &storage.CSIDriverList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched cSIDriver.
|
||||
func (c *FakeCSIDrivers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *storage.CSIDriver, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootPatchSubresourceAction(csidriversResource, name, pt, data, subresources...), &storage.CSIDriver{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*storage.CSIDriver), err
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
storage "k8s.io/kubernetes/pkg/apis/storage"
|
||||
)
|
||||
|
||||
// FakeCSINodes implements CSINodeInterface
|
||||
type FakeCSINodes struct {
|
||||
Fake *FakeStorage
|
||||
}
|
||||
|
||||
var csinodesResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "", Resource: "csinodes"}
|
||||
|
||||
var csinodesKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "", Kind: "CSINode"}
|
||||
|
||||
// Get takes name of the cSINode, and returns the corresponding cSINode object, and an error if there is any.
|
||||
func (c *FakeCSINodes) Get(name string, options v1.GetOptions) (result *storage.CSINode, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootGetAction(csinodesResource, name), &storage.CSINode{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*storage.CSINode), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of CSINodes that match those selectors.
|
||||
func (c *FakeCSINodes) List(opts v1.ListOptions) (result *storage.CSINodeList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootListAction(csinodesResource, csinodesKind, opts), &storage.CSINodeList{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &storage.CSINodeList{ListMeta: obj.(*storage.CSINodeList).ListMeta}
|
||||
for _, item := range obj.(*storage.CSINodeList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested cSINodes.
|
||||
func (c *FakeCSINodes) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewRootWatchAction(csinodesResource, opts))
|
||||
}
|
||||
|
||||
// Create takes the representation of a cSINode and creates it. Returns the server's representation of the cSINode, and an error, if there is any.
|
||||
func (c *FakeCSINodes) Create(cSINode *storage.CSINode) (result *storage.CSINode, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootCreateAction(csinodesResource, cSINode), &storage.CSINode{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*storage.CSINode), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a cSINode and updates it. Returns the server's representation of the cSINode, and an error, if there is any.
|
||||
func (c *FakeCSINodes) Update(cSINode *storage.CSINode) (result *storage.CSINode, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootUpdateAction(csinodesResource, cSINode), &storage.CSINode{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*storage.CSINode), err
|
||||
}
|
||||
|
||||
// Delete takes name of the cSINode and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeCSINodes) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewRootDeleteAction(csinodesResource, name), &storage.CSINode{})
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeCSINodes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewRootDeleteCollectionAction(csinodesResource, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &storage.CSINodeList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched cSINode.
|
||||
func (c *FakeCSINodes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *storage.CSINode, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootPatchSubresourceAction(csinodesResource, name, pt, data, subresources...), &storage.CSINode{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*storage.CSINode), err
|
||||
}
|
|
@ -28,6 +28,14 @@ type FakeStorage struct {
|
|||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeStorage) CSIDrivers() internalversion.CSIDriverInterface {
|
||||
return &FakeCSIDrivers{c}
|
||||
}
|
||||
|
||||
func (c *FakeStorage) CSINodes() internalversion.CSINodeInterface {
|
||||
return &FakeCSINodes{c}
|
||||
}
|
||||
|
||||
func (c *FakeStorage) StorageClasses() internalversion.StorageClassInterface {
|
||||
return &FakeStorageClasses{c}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@ limitations under the License.
|
|||
|
||||
package internalversion
|
||||
|
||||
type CSIDriverExpansion interface{}
|
||||
|
||||
type CSINodeExpansion interface{}
|
||||
|
||||
type StorageClassExpansion interface{}
|
||||
|
||||
type VolumeAttachmentExpansion interface{}
|
||||
|
|
|
@ -25,6 +25,8 @@ import (
|
|||
|
||||
type StorageInterface interface {
|
||||
RESTClient() rest.Interface
|
||||
CSIDriversGetter
|
||||
CSINodesGetter
|
||||
StorageClassesGetter
|
||||
VolumeAttachmentsGetter
|
||||
}
|
||||
|
@ -34,6 +36,14 @@ type StorageClient struct {
|
|||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *StorageClient) CSIDrivers() CSIDriverInterface {
|
||||
return newCSIDrivers(c)
|
||||
}
|
||||
|
||||
func (c *StorageClient) CSINodes() CSINodeInterface {
|
||||
return newCSINodes(c)
|
||||
}
|
||||
|
||||
func (c *StorageClient) StorageClasses() StorageClassInterface {
|
||||
return newStorageClasses(c)
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ go_library(
|
|||
"//staging/src/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/workqueue:go_default_library",
|
||||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -39,7 +39,6 @@ import (
|
|||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
csiclient "k8s.io/csi-api/pkg/client/clientset/versioned"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache"
|
||||
|
@ -98,7 +97,6 @@ type AttachDetachController interface {
|
|||
// NewAttachDetachController returns a new instance of AttachDetachController.
|
||||
func NewAttachDetachController(
|
||||
kubeClient clientset.Interface,
|
||||
csiClient csiclient.Interface,
|
||||
podInformer coreinformers.PodInformer,
|
||||
nodeInformer coreinformers.NodeInformer,
|
||||
pvcInformer coreinformers.PersistentVolumeClaimInformer,
|
||||
|
@ -125,7 +123,6 @@ func NewAttachDetachController(
|
|||
// deleted (probably can't do this with sharedInformer), etc.
|
||||
adc := &attachDetachController{
|
||||
kubeClient: kubeClient,
|
||||
csiClient: csiClient,
|
||||
pvcLister: pvcInformer.Lister(),
|
||||
pvcsSynced: pvcInformer.Informer().HasSynced,
|
||||
pvLister: pvInformer.Lister(),
|
||||
|
@ -241,10 +238,6 @@ type attachDetachController struct {
|
|||
// the API server.
|
||||
kubeClient clientset.Interface
|
||||
|
||||
// csiClient is the csi.storage.k8s.io API client used by volumehost to communicate with
|
||||
// the API server.
|
||||
csiClient csiclient.Interface
|
||||
|
||||
// pvcLister is the shared PVC lister used to fetch and store PVC
|
||||
// objects from the API server. It is shared with other controllers and
|
||||
// therefore the PVC objects in its store should be treated as immutable.
|
||||
|
@ -766,10 +759,6 @@ func (adc *attachDetachController) GetEventRecorder() record.EventRecorder {
|
|||
return adc.recorder
|
||||
}
|
||||
|
||||
func (adc *attachDetachController) GetCSIClient() csiclient.Interface {
|
||||
return adc.csiClient
|
||||
}
|
||||
|
||||
func (adc *attachDetachController) GetSubpather() subpath.Interface {
|
||||
// Subpaths not needed in attachdetach controller
|
||||
return nil
|
||||
|
|
|
@ -40,7 +40,6 @@ func Test_NewAttachDetachController_Positive(t *testing.T) {
|
|||
// Act
|
||||
_, err := NewAttachDetachController(
|
||||
fakeKubeClient,
|
||||
nil, /* csiClient */
|
||||
informerFactory.Core().V1().Pods(),
|
||||
informerFactory.Core().V1().Nodes(),
|
||||
informerFactory.Core().V1().PersistentVolumeClaims(),
|
||||
|
@ -215,7 +214,6 @@ func attachDetachRecoveryTestCase(t *testing.T, extraPods1 []*v1.Pod, extraPods2
|
|||
// Create the controller
|
||||
adcObj, err := NewAttachDetachController(
|
||||
fakeKubeClient,
|
||||
nil, /* csiClient */
|
||||
informerFactory.Core().V1().Pods(),
|
||||
informerFactory.Core().V1().Nodes(),
|
||||
informerFactory.Core().V1().PersistentVolumeClaims(),
|
||||
|
|
|
@ -36,7 +36,6 @@ go_library(
|
|||
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -38,7 +38,6 @@ import (
|
|||
kcache "k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/controller/volume/events"
|
||||
"k8s.io/kubernetes/pkg/controller/volume/expand/cache"
|
||||
|
@ -336,11 +335,6 @@ func (expc *expandController) GetEventRecorder() record.EventRecorder {
|
|||
return expc.recorder
|
||||
}
|
||||
|
||||
func (expc *expandController) GetCSIClient() csiclientset.Interface {
|
||||
// No volume plugin in expand controller needs csi.storage.k8s.io
|
||||
return nil
|
||||
}
|
||||
|
||||
func (expc *expandController) GetSubpather() subpath.Interface {
|
||||
// not needed for expand controller
|
||||
return nil
|
||||
|
|
|
@ -61,7 +61,6 @@ go_library(
|
|||
"//staging/src/k8s.io/client-go/util/workqueue:go_default_library",
|
||||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||
"//staging/src/k8s.io/cloud-provider/volume/errors:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library",
|
||||
"//staging/src/k8s.io/csi-translation-lib:go_default_library",
|
||||
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
|
|
|
@ -26,7 +26,6 @@ import (
|
|||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/record"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
vol "k8s.io/kubernetes/pkg/volume"
|
||||
|
@ -133,11 +132,6 @@ func (ctrl *PersistentVolumeController) GetEventRecorder() record.EventRecorder
|
|||
return ctrl.eventRecorder
|
||||
}
|
||||
|
||||
func (ctrl *PersistentVolumeController) GetCSIClient() csiclientset.Interface {
|
||||
// No volume plugin needs csi.storage.k8s.io client in PV controller.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctrl *PersistentVolumeController) GetSubpather() subpath.Interface {
|
||||
// No volume plugin needs Subpaths in PV controller.
|
||||
return nil
|
||||
|
|
|
@ -195,12 +195,14 @@ const (
|
|||
|
||||
// owner: @saad-ali
|
||||
// alpha: v1.12
|
||||
// Enable all logic related to the CSIDriver API object in csi.storage.k8s.io
|
||||
// beta: v1.14
|
||||
// Enable all logic related to the CSIDriver API object in storage.k8s.io
|
||||
CSIDriverRegistry utilfeature.Feature = "CSIDriverRegistry"
|
||||
|
||||
// owner: @verult
|
||||
// alpha: v1.12
|
||||
// Enable all logic related to the CSINodeInfo API object in csi.storage.k8s.io
|
||||
// beta: v1.14
|
||||
// Enable all logic related to the CSINode API object in storage.k8s.io
|
||||
CSINodeInfo utilfeature.Feature = "CSINodeInfo"
|
||||
|
||||
// owner @MrHohn
|
||||
|
@ -448,8 +450,8 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
|
|||
MountContainers: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
VolumeScheduling: {Default: true, PreRelease: utilfeature.GA, LockToDefault: true}, // remove in 1.16
|
||||
CSIPersistentVolume: {Default: true, PreRelease: utilfeature.GA},
|
||||
CSIDriverRegistry: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
CSINodeInfo: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
CSIDriverRegistry: {Default: true, PreRelease: utilfeature.Beta},
|
||||
CSINodeInfo: {Default: true, PreRelease: utilfeature.Beta},
|
||||
CustomPodDNS: {Default: true, PreRelease: utilfeature.GA, LockToDefault: true}, // remove in 1.16
|
||||
BlockVolume: {Default: true, PreRelease: utilfeature.Beta},
|
||||
StorageObjectInUseProtection: {Default: true, PreRelease: utilfeature.GA},
|
||||
|
|
|
@ -21,6 +21,8 @@ go_library(
|
|||
"//pkg/apis/extensions:go_default_library",
|
||||
"//pkg/apis/networking:go_default_library",
|
||||
"//pkg/apis/policy:go_default_library",
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/server/options:go_default_library",
|
||||
|
@ -28,6 +30,7 @@ go_library(
|
|||
"//staging/src/k8s.io/apiserver/pkg/server/resourceconfig:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/server/storage:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"k8s.io/apiserver/pkg/server/resourceconfig"
|
||||
serverstorage "k8s.io/apiserver/pkg/server/storage"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
|
@ -34,6 +35,8 @@ import (
|
|||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/apis/networking"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
apisstorage "k8s.io/kubernetes/pkg/apis/storage"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
// SpecialDefaultResourcePrefixes are prefixes compiled into Kubernetes.
|
||||
|
@ -48,12 +51,23 @@ var SpecialDefaultResourcePrefixes = map[schema.GroupResource]string{
|
|||
}
|
||||
|
||||
func NewStorageFactoryConfig() *StorageFactoryConfig {
|
||||
|
||||
resources := []schema.GroupVersionResource{
|
||||
batch.Resource("cronjobs").WithVersion("v1beta1"),
|
||||
}
|
||||
// add csinodes if CSINodeInfo feature gate is enabled
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) {
|
||||
resources = append(resources, apisstorage.Resource("csinodes").WithVersion("v1beta1"))
|
||||
}
|
||||
// add csidrivers if CSIDriverRegistry feature gate is enabled
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) {
|
||||
resources = append(resources, apisstorage.Resource("csidrivers").WithVersion("v1beta1"))
|
||||
}
|
||||
|
||||
return &StorageFactoryConfig{
|
||||
Serializer: legacyscheme.Codecs,
|
||||
DefaultResourceEncoding: serverstorage.NewDefaultResourceEncodingConfig(legacyscheme.Scheme),
|
||||
ResourceEncodingOverrides: []schema.GroupVersionResource{
|
||||
batch.Resource("cronjobs").WithVersion("v1beta1"),
|
||||
},
|
||||
Serializer: legacyscheme.Codecs,
|
||||
DefaultResourceEncoding: serverstorage.NewDefaultResourceEncodingConfig(legacyscheme.Scheme),
|
||||
ResourceEncodingOverrides: resources,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -140,7 +140,6 @@ go_library(
|
|||
"//staging/src/k8s.io/client-go/util/certificate:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library",
|
||||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library",
|
||||
"//staging/src/k8s.io/node-api/pkg/client/clientset/versioned:go_default_library",
|
||||
"//third_party/forked/golang/expansion:go_default_library",
|
||||
"//vendor/github.com/golang/groupcache/lru:go_default_library",
|
||||
|
|
|
@ -51,7 +51,6 @@ import (
|
|||
"k8s.io/client-go/util/certificate"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned"
|
||||
"k8s.io/klog"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
|
@ -249,7 +248,6 @@ type Dependencies struct {
|
|||
HeartbeatClient clientset.Interface
|
||||
OnHeartbeatFailure func()
|
||||
KubeClient clientset.Interface
|
||||
CSIClient csiclientset.Interface
|
||||
NodeAPIClient nodeapiclientset.Interface
|
||||
Mounter mount.Interface
|
||||
OOMAdjuster *oom.OOMAdjuster
|
||||
|
@ -493,7 +491,6 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
|
|||
hostnameOverridden: len(hostnameOverride) > 0,
|
||||
nodeName: nodeName,
|
||||
kubeClient: kubeDeps.KubeClient,
|
||||
csiClient: kubeDeps.CSIClient,
|
||||
heartbeatClient: kubeDeps.HeartbeatClient,
|
||||
onRepeatedHeartbeatFailure: kubeDeps.OnHeartbeatFailure,
|
||||
rootDirectory: rootDirectory,
|
||||
|
@ -898,7 +895,6 @@ type Kubelet struct {
|
|||
nodeName types.NodeName
|
||||
runtimeCache kubecontainer.RuntimeCache
|
||||
kubeClient clientset.Interface
|
||||
csiClient csiclientset.Interface
|
||||
heartbeatClient clientset.Interface
|
||||
iptClient utilipt.Interface
|
||||
rootDirectory string
|
||||
|
|
|
@ -30,7 +30,6 @@ import (
|
|||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/record"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/kubelet/configmap"
|
||||
"k8s.io/kubernetes/pkg/kubelet/container"
|
||||
|
@ -123,10 +122,6 @@ func (kvh *kubeletVolumeHost) GetKubeClient() clientset.Interface {
|
|||
return kvh.kubelet.kubeClient
|
||||
}
|
||||
|
||||
func (kvh *kubeletVolumeHost) GetCSIClient() csiclientset.Interface {
|
||||
return kvh.kubelet.csiClient
|
||||
}
|
||||
|
||||
func (kvh *kubeletVolumeHost) GetSubpather() subpath.Interface {
|
||||
return kvh.kubelet.subpather
|
||||
}
|
||||
|
|
|
@ -85,6 +85,8 @@ filegroup(
|
|||
"//pkg/registry/scheduling/rest:all-srcs",
|
||||
"//pkg/registry/settings/podpreset:all-srcs",
|
||||
"//pkg/registry/settings/rest:all-srcs",
|
||||
"//pkg/registry/storage/csidriver:all-srcs",
|
||||
"//pkg/registry/storage/csinode:all-srcs",
|
||||
"//pkg/registry/storage/rest:all-srcs",
|
||||
"//pkg/registry/storage/storageclass:all-srcs",
|
||||
"//pkg/registry/storage/volumeattachment:all-srcs",
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"strategy.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/registry/storage/csidriver",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/apis/storage/validation:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/registry/storage/csidriver/storage:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["strategy_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package csidriver provides Registry interface and its REST
|
||||
// implementation for storing csidriver api objects.
|
||||
package csidriver
|
|
@ -0,0 +1,48 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["storage.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/registry/storage/csidriver/storage",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/registry/storage/csidriver:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["storage_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/registry/registrytest:go_default_library",
|
||||
"//staging/src/k8s.io/api/storage/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic/testing:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
storageapi "k8s.io/kubernetes/pkg/apis/storage"
|
||||
"k8s.io/kubernetes/pkg/registry/storage/csidriver"
|
||||
)
|
||||
|
||||
// CSIDriverStorage includes storage for CSIDrivers and all subresources
|
||||
type CSIDriverStorage struct {
|
||||
CSIDriver *REST
|
||||
}
|
||||
|
||||
// REST object that will work for CSIDrivers
|
||||
type REST struct {
|
||||
*genericregistry.Store
|
||||
}
|
||||
|
||||
// NewStorage returns a RESTStorage object that will work against CSIDrivers
|
||||
func NewStorage(optsGetter generic.RESTOptionsGetter) *CSIDriverStorage {
|
||||
store := &genericregistry.Store{
|
||||
NewFunc: func() runtime.Object { return &storageapi.CSIDriver{} },
|
||||
NewListFunc: func() runtime.Object { return &storageapi.CSIDriverList{} },
|
||||
DefaultQualifiedResource: storageapi.Resource("csidrivers"),
|
||||
|
||||
CreateStrategy: csidriver.Strategy,
|
||||
UpdateStrategy: csidriver.Strategy,
|
||||
DeleteStrategy: csidriver.Strategy,
|
||||
ReturnDeletedObject: true,
|
||||
}
|
||||
options := &generic.StoreOptions{RESTOptions: optsGetter}
|
||||
if err := store.CompleteWithOptions(options); err != nil {
|
||||
panic(err) // TODO: Propagate error up
|
||||
}
|
||||
|
||||
return &CSIDriverStorage{
|
||||
CSIDriver: &REST{store},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
storageapiv1beta1 "k8s.io/api/storage/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing"
|
||||
etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
storageapi "k8s.io/kubernetes/pkg/apis/storage"
|
||||
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||
)
|
||||
|
||||
func newStorage(t *testing.T) (*REST, *etcdtesting.EtcdTestServer) {
|
||||
etcdStorage, server := registrytest.NewEtcdStorage(t, storageapi.GroupName)
|
||||
restOptions := generic.RESTOptions{
|
||||
StorageConfig: etcdStorage,
|
||||
Decorator: generic.UndecoratedStorage,
|
||||
DeleteCollectionWorkers: 1,
|
||||
ResourcePrefix: "csidrivers",
|
||||
}
|
||||
csiDriverStorage := NewStorage(restOptions)
|
||||
return csiDriverStorage.CSIDriver, server
|
||||
}
|
||||
|
||||
func validNewCSIDriver(name string) *storageapi.CSIDriver {
|
||||
attachRequired := true
|
||||
podInfoOnMount := true
|
||||
return &storageapi.CSIDriver{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
Spec: storageapi.CSIDriverSpec{
|
||||
AttachRequired: &attachRequired,
|
||||
PodInfoOnMount: &podInfoOnMount,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion {
|
||||
// skip the test for all versions exception v1beta1
|
||||
return
|
||||
}
|
||||
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
csiDriver := validNewCSIDriver("foo")
|
||||
csiDriver.ObjectMeta = metav1.ObjectMeta{GenerateName: "foo"}
|
||||
attachNotRequired := false
|
||||
notPodInfoOnMount := false
|
||||
test.TestCreate(
|
||||
// valid
|
||||
csiDriver,
|
||||
// invalid
|
||||
&storageapi.CSIDriver{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "*BadName!"},
|
||||
Spec: storageapi.CSIDriverSpec{
|
||||
AttachRequired: &attachNotRequired,
|
||||
PodInfoOnMount: ¬PodInfoOnMount,
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion {
|
||||
// skip the test for all versions exception v1beta1
|
||||
return
|
||||
}
|
||||
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
notPodInfoOnMount := false
|
||||
|
||||
test.TestUpdate(
|
||||
// valid
|
||||
validNewCSIDriver("foo"),
|
||||
//invalid update
|
||||
func(obj runtime.Object) runtime.Object {
|
||||
object := obj.(*storageapi.CSIDriver)
|
||||
object.Spec.PodInfoOnMount = ¬PodInfoOnMount
|
||||
return object
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion {
|
||||
// skip the test for all versions exception v1beta1
|
||||
return
|
||||
}
|
||||
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope().ReturnDeletedObject()
|
||||
test.TestDelete(validNewCSIDriver("foo"))
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion {
|
||||
// skip the test for all versions exception v1beta1
|
||||
return
|
||||
}
|
||||
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
test.TestGet(validNewCSIDriver("foo"))
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion {
|
||||
// skip the test for all versions exception v1beta1
|
||||
return
|
||||
}
|
||||
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
test.TestList(validNewCSIDriver("foo"))
|
||||
}
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion {
|
||||
// skip the test for all versions exception v1beta1
|
||||
return
|
||||
}
|
||||
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
test.TestWatch(
|
||||
validNewCSIDriver("foo"),
|
||||
// matching labels
|
||||
[]labels.Set{},
|
||||
// not matching labels
|
||||
[]labels.Set{
|
||||
{"foo": "bar"},
|
||||
},
|
||||
// matching fields
|
||||
[]fields.Set{
|
||||
{"metadata.name": "foo"},
|
||||
},
|
||||
// not matching fields
|
||||
[]fields.Set{
|
||||
{"metadata.name": "bar"},
|
||||
},
|
||||
)
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package csidriver
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
"k8s.io/kubernetes/pkg/apis/storage/validation"
|
||||
)
|
||||
|
||||
// csiDriverStrategy implements behavior for CSIDriver objects
|
||||
type csiDriverStrategy struct {
|
||||
runtime.ObjectTyper
|
||||
names.NameGenerator
|
||||
}
|
||||
|
||||
// Strategy is the default logic that applies when creating and updating
|
||||
// CSIDriver objects via the REST API.
|
||||
var Strategy = csiDriverStrategy{legacyscheme.Scheme, names.SimpleNameGenerator}
|
||||
|
||||
func (csiDriverStrategy) NamespaceScoped() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ResetBeforeCreate clears the Status field which is not allowed to be set by end users on creation.
|
||||
func (csiDriverStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
}
|
||||
|
||||
func (csiDriverStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
||||
csiDriver := obj.(*storage.CSIDriver)
|
||||
|
||||
errs := validation.ValidateCSIDriver(csiDriver)
|
||||
errs = append(errs, validation.ValidateCSIDriver(csiDriver)...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (csiDriverStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
|
||||
func (csiDriverStrategy) AllowCreateOnUpdate() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// PrepareForUpdate sets the Status fields which is not allowed to be set by an end user updating a CSIDriver
|
||||
func (csiDriverStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||
}
|
||||
|
||||
func (csiDriverStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
newCSIDriverObj := obj.(*storage.CSIDriver)
|
||||
oldCSIDriverObj := old.(*storage.CSIDriver)
|
||||
errorList := validation.ValidateCSIDriver(newCSIDriverObj)
|
||||
return append(errorList, validation.ValidateCSIDriverUpdate(newCSIDriverObj, oldCSIDriverObj)...)
|
||||
}
|
||||
|
||||
func (csiDriverStrategy) AllowUnconditionalUpdate() bool {
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package csidriver
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
)
|
||||
|
||||
func getValidCSIDriver(name string) *storage.CSIDriver {
|
||||
attachRequired := true
|
||||
podInfoOnMount := true
|
||||
return &storage.CSIDriver{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachRequired,
|
||||
PodInfoOnMount: &podInfoOnMount,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSIDriverStrategy(t *testing.T) {
|
||||
ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
|
||||
APIGroup: "storage.k8s.io",
|
||||
APIVersion: "v1beta1",
|
||||
Resource: "csidrivers",
|
||||
})
|
||||
if Strategy.NamespaceScoped() {
|
||||
t.Errorf("CSIDriver must not be namespace scoped")
|
||||
}
|
||||
if Strategy.AllowCreateOnUpdate() {
|
||||
t.Errorf("CSIDriver should not allow create on update")
|
||||
}
|
||||
|
||||
csiDriver := getValidCSIDriver("valid-csidriver")
|
||||
|
||||
Strategy.PrepareForCreate(ctx, csiDriver)
|
||||
|
||||
errs := Strategy.Validate(ctx, csiDriver)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("unexpected error validating %v", errs)
|
||||
}
|
||||
|
||||
// Update of spec is disallowed
|
||||
newCSIDriver := csiDriver.DeepCopy()
|
||||
attachNotRequired := false
|
||||
newCSIDriver.Spec.AttachRequired = &attachNotRequired
|
||||
|
||||
Strategy.PrepareForUpdate(ctx, newCSIDriver, csiDriver)
|
||||
|
||||
errs = Strategy.ValidateUpdate(ctx, newCSIDriver, csiDriver)
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("Expected a validation error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSIDriverValidation(t *testing.T) {
|
||||
attachRequired := true
|
||||
notAttachRequired := false
|
||||
podInfoOnMount := true
|
||||
notPodInfoOnMount := false
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
csiDriver *storage.CSIDriver
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
"valid csidriver",
|
||||
getValidCSIDriver("foo"),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"true PodInfoOnMount and AttachRequired",
|
||||
&storage.CSIDriver{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachRequired,
|
||||
PodInfoOnMount: &podInfoOnMount,
|
||||
},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"false PodInfoOnMount and AttachRequired",
|
||||
&storage.CSIDriver{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: ¬AttachRequired,
|
||||
PodInfoOnMount: ¬PodInfoOnMount,
|
||||
},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid driver name",
|
||||
&storage.CSIDriver{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "*foo#",
|
||||
},
|
||||
Spec: storage.CSIDriverSpec{
|
||||
AttachRequired: &attachRequired,
|
||||
PodInfoOnMount: &podInfoOnMount,
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
testValidation := func(csiDriver *storage.CSIDriver, apiVersion string) field.ErrorList {
|
||||
ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
|
||||
APIGroup: "storage.k8s.io",
|
||||
APIVersion: "v1beta1",
|
||||
Resource: "csidrivers",
|
||||
})
|
||||
return Strategy.Validate(ctx, csiDriver)
|
||||
}
|
||||
|
||||
betaErr := testValidation(test.csiDriver, "v1beta1")
|
||||
if len(betaErr) > 0 && !test.expectError {
|
||||
t.Errorf("Validation of v1beta1 object failed: %+v", betaErr)
|
||||
}
|
||||
if len(betaErr) == 0 && test.expectError {
|
||||
t.Errorf("Validation of v1beta1 object unexpectedly succeeded")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"strategy.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/registry/storage/csinode",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/apis/storage/validation:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/registry/storage/csinode/storage:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["strategy_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package csinode provides Registry interface and its REST
|
||||
// implementation for storing csinode api objects.
|
||||
package csinode
|
|
@ -0,0 +1,48 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["storage.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/registry/storage/csinode/storage",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/registry/storage/csinode:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["storage_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/registry/registrytest:go_default_library",
|
||||
"//staging/src/k8s.io/api/storage/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic/testing:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library",
|
||||
],
|
||||
)
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
storageapi "k8s.io/kubernetes/pkg/apis/storage"
|
||||
"k8s.io/kubernetes/pkg/registry/storage/csinode"
|
||||
)
|
||||
|
||||
// CSINodeStorage includes storage for CSINodes and all subresources
|
||||
type CSINodeStorage struct {
|
||||
CSINode *REST
|
||||
}
|
||||
|
||||
// REST object that will work for CSINodes
|
||||
type REST struct {
|
||||
*genericregistry.Store
|
||||
}
|
||||
|
||||
// NewStorage returns a RESTStorage object that will work against CSINodes
|
||||
func NewStorage(optsGetter generic.RESTOptionsGetter) *CSINodeStorage {
|
||||
store := &genericregistry.Store{
|
||||
NewFunc: func() runtime.Object { return &storageapi.CSINode{} },
|
||||
NewListFunc: func() runtime.Object { return &storageapi.CSINodeList{} },
|
||||
DefaultQualifiedResource: storageapi.Resource("csinodes"),
|
||||
|
||||
CreateStrategy: csinode.Strategy,
|
||||
UpdateStrategy: csinode.Strategy,
|
||||
DeleteStrategy: csinode.Strategy,
|
||||
ReturnDeletedObject: true,
|
||||
}
|
||||
options := &generic.StoreOptions{RESTOptions: optsGetter}
|
||||
if err := store.CompleteWithOptions(options); err != nil {
|
||||
panic(err) // TODO: Propagate error up
|
||||
}
|
||||
|
||||
return &CSINodeStorage{
|
||||
CSINode: &REST{store},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
storageapiv1beta1 "k8s.io/api/storage/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing"
|
||||
etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
storageapi "k8s.io/kubernetes/pkg/apis/storage"
|
||||
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||
)
|
||||
|
||||
func newStorage(t *testing.T) (*REST, *etcdtesting.EtcdTestServer) {
|
||||
etcdStorage, server := registrytest.NewEtcdStorage(t, storageapi.GroupName)
|
||||
restOptions := generic.RESTOptions{
|
||||
StorageConfig: etcdStorage,
|
||||
Decorator: generic.UndecoratedStorage,
|
||||
DeleteCollectionWorkers: 1,
|
||||
ResourcePrefix: "csinodes",
|
||||
}
|
||||
csiNodeStorage := NewStorage(restOptions)
|
||||
return csiNodeStorage.CSINode, server
|
||||
}
|
||||
|
||||
func validNewCSINode(name string) *storageapi.CSINode {
|
||||
return &storageapi.CSINode{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
Spec: storageapi.CSINodeSpec{
|
||||
Drivers: []storageapi.CSINodeDriver{
|
||||
{
|
||||
Name: "valid-driver-name",
|
||||
NodeID: "valid-node",
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion {
|
||||
// skip the test for all versions exception v1beta1
|
||||
return
|
||||
}
|
||||
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
csiNode := validNewCSINode("foo")
|
||||
csiNode.ObjectMeta = metav1.ObjectMeta{GenerateName: "foo"}
|
||||
test.TestCreate(
|
||||
// valid
|
||||
csiNode,
|
||||
// invalid
|
||||
&storageapi.CSINode{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "*BadName!"},
|
||||
Spec: storageapi.CSINodeSpec{
|
||||
Drivers: []storageapi.CSINodeDriver{
|
||||
{
|
||||
Name: "invalid-name-!@#$%^&*()",
|
||||
NodeID: "invalid-node-!@#$%^&*()",
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion {
|
||||
// skip the test for all versions exception v1beta1
|
||||
return
|
||||
}
|
||||
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
|
||||
test.TestUpdate(
|
||||
// valid
|
||||
validNewCSINode("foo"),
|
||||
// we allow status field to be set in v1beta1
|
||||
func(obj runtime.Object) runtime.Object {
|
||||
object := obj.(*storageapi.CSINode)
|
||||
//object.Status = *getCSINodeStatus()
|
||||
return object
|
||||
},
|
||||
//invalid update
|
||||
func(obj runtime.Object) runtime.Object {
|
||||
object := obj.(*storageapi.CSINode)
|
||||
object.Spec.Drivers[0].Name = "invalid-name-!@#$%^&*()"
|
||||
return object
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion {
|
||||
// skip the test for all versions exception v1beta1
|
||||
return
|
||||
}
|
||||
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope().ReturnDeletedObject()
|
||||
test.TestDelete(validNewCSINode("foo"))
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion {
|
||||
// skip the test for all versions exception v1beta1
|
||||
return
|
||||
}
|
||||
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
test.TestGet(validNewCSINode("foo"))
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion {
|
||||
// skip the test for all versions exception v1beta1
|
||||
return
|
||||
}
|
||||
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
test.TestList(validNewCSINode("foo"))
|
||||
}
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion {
|
||||
// skip the test for all versions exception v1beta1
|
||||
return
|
||||
}
|
||||
|
||||
storage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
test.TestWatch(
|
||||
validNewCSINode("foo"),
|
||||
// matching labels
|
||||
[]labels.Set{},
|
||||
// not matching labels
|
||||
[]labels.Set{
|
||||
{"foo": "bar"},
|
||||
},
|
||||
// matching fields
|
||||
[]fields.Set{
|
||||
{"metadata.name": "foo"},
|
||||
},
|
||||
// not matching fields
|
||||
[]fields.Set{
|
||||
{"metadata.name": "bar"},
|
||||
},
|
||||
)
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package csinode
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
"k8s.io/kubernetes/pkg/apis/storage/validation"
|
||||
)
|
||||
|
||||
// csiNodeStrategy implements behavior for CSINode objects
|
||||
type csiNodeStrategy struct {
|
||||
runtime.ObjectTyper
|
||||
names.NameGenerator
|
||||
}
|
||||
|
||||
// Strategy is the default logic that applies when creating and updating
|
||||
// CSINode objects via the REST API.
|
||||
var Strategy = csiNodeStrategy{legacyscheme.Scheme, names.SimpleNameGenerator}
|
||||
|
||||
func (csiNodeStrategy) NamespaceScoped() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ResetBeforeCreate clears the Status field which is not allowed to be set by end users on creation.
|
||||
func (csiNodeStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
}
|
||||
|
||||
func (csiNodeStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
||||
csiNode := obj.(*storage.CSINode)
|
||||
|
||||
errs := validation.ValidateCSINode(csiNode)
|
||||
errs = append(errs, validation.ValidateCSINode(csiNode)...)
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (csiNodeStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
|
||||
func (csiNodeStrategy) AllowCreateOnUpdate() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// PrepareForUpdate sets the Status fields which is not allowed to be set by an end user updating a CSINode
|
||||
func (csiNodeStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||
}
|
||||
|
||||
func (csiNodeStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
newCSINodeObj := obj.(*storage.CSINode)
|
||||
oldCSINodeObj := old.(*storage.CSINode)
|
||||
errorList := validation.ValidateCSINode(newCSINodeObj)
|
||||
return append(errorList, validation.ValidateCSINodeUpdate(newCSINodeObj, oldCSINodeObj)...)
|
||||
}
|
||||
|
||||
func (csiNodeStrategy) AllowUnconditionalUpdate() bool {
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package csinode
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
)
|
||||
|
||||
func getValidCSINode(name string) *storage.CSINode {
|
||||
return &storage.CSINode{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "valid-driver-name",
|
||||
NodeID: "valid-node",
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSINodeStrategy(t *testing.T) {
|
||||
ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
|
||||
APIGroup: "storage.k8s.io",
|
||||
APIVersion: "v1beta1",
|
||||
Resource: "csinodes",
|
||||
})
|
||||
if Strategy.NamespaceScoped() {
|
||||
t.Errorf("CSINode must not be namespace scoped")
|
||||
}
|
||||
if Strategy.AllowCreateOnUpdate() {
|
||||
t.Errorf("CSINode should not allow create on update")
|
||||
}
|
||||
|
||||
csiNode := getValidCSINode("valid-csinode")
|
||||
|
||||
Strategy.PrepareForCreate(ctx, csiNode)
|
||||
|
||||
errs := Strategy.Validate(ctx, csiNode)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("unexpected error validating %v", errs)
|
||||
}
|
||||
|
||||
// Update of spec is allowed
|
||||
newCSINode := csiNode.DeepCopy()
|
||||
newCSINode.Spec.Drivers[0].NodeID = "valid-node-2"
|
||||
|
||||
Strategy.PrepareForUpdate(ctx, newCSINode, csiNode)
|
||||
|
||||
errs = Strategy.ValidateUpdate(ctx, newCSINode, csiNode)
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("expected validation error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSINodeValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
csiNode *storage.CSINode
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
"valid csinode",
|
||||
getValidCSINode("foo"),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid driver name",
|
||||
&storage.CSINode{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "$csi-driver@",
|
||||
NodeID: "valid-node",
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"empty node id",
|
||||
&storage.CSINode{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "valid-driver-name",
|
||||
NodeID: "",
|
||||
TopologyKeys: []string{"company.com/zone1", "company.com/zone2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid topology keys",
|
||||
&storage.CSINode{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "valid-driver-name",
|
||||
NodeID: "valid-node",
|
||||
TopologyKeys: []string{"company.com/zone1", ""},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
testValidation := func(csiNode *storage.CSINode, apiVersion string) field.ErrorList {
|
||||
ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{
|
||||
APIGroup: "storage.k8s.io",
|
||||
APIVersion: "v1beta1",
|
||||
Resource: "csinodes",
|
||||
})
|
||||
return Strategy.Validate(ctx, csiNode)
|
||||
}
|
||||
|
||||
betaErr := testValidation(test.csiNode, "v1beta1")
|
||||
if len(betaErr) > 0 && !test.expectError {
|
||||
t.Errorf("Validation of v1beta1 object failed: %+v", betaErr)
|
||||
}
|
||||
if len(betaErr) == 0 && test.expectError {
|
||||
t.Errorf("Validation of v1beta1 object unexpectedly succeeded")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -12,6 +12,9 @@ go_library(
|
|||
deps = [
|
||||
"//pkg/api/legacyscheme:go_default_library",
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/registry/storage/csidriver/storage:go_default_library",
|
||||
"//pkg/registry/storage/csinode/storage:go_default_library",
|
||||
"//pkg/registry/storage/storageclass/storage:go_default_library",
|
||||
"//pkg/registry/storage/volumeattachment/storage:go_default_library",
|
||||
"//staging/src/k8s.io/api/storage/v1:go_default_library",
|
||||
|
@ -21,6 +24,7 @@ go_library(
|
|||
"//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/server:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/server/storage:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -24,8 +24,12 @@ import (
|
|||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
serverstorage "k8s.io/apiserver/pkg/server/storage"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
storageapi "k8s.io/kubernetes/pkg/apis/storage"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
csidriverstore "k8s.io/kubernetes/pkg/registry/storage/csidriver/storage"
|
||||
csinodestore "k8s.io/kubernetes/pkg/registry/storage/csinode/storage"
|
||||
storageclassstore "k8s.io/kubernetes/pkg/registry/storage/storageclass/storage"
|
||||
volumeattachmentstore "k8s.io/kubernetes/pkg/registry/storage/volumeattachment/storage"
|
||||
)
|
||||
|
@ -70,6 +74,18 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag
|
|||
volumeAttachmentStorage := volumeattachmentstore.NewStorage(restOptionsGetter)
|
||||
storage["volumeattachments"] = volumeAttachmentStorage.VolumeAttachment
|
||||
|
||||
// register csinodes if CSINodeInfo feature gate is enabled
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) {
|
||||
csiNodeStorage := csinodestore.NewStorage(restOptionsGetter)
|
||||
storage["csinodes"] = csiNodeStorage.CSINode
|
||||
}
|
||||
|
||||
// register csidrivers if CSIDriverRegistry feature gate is enabled
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) {
|
||||
csiDriverStorage := csidriverstore.NewStorage(restOptionsGetter)
|
||||
storage["csidrivers"] = csiDriverStorage.CSIDriver
|
||||
}
|
||||
|
||||
return storage
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ go_library(
|
|||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -28,10 +28,10 @@ go_library(
|
|||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/informers:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/informers/storage/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/informers/externalversions:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/informers/externalversions/csi/v1alpha1:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/listers/csi/v1alpha1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/listers/storage/v1beta1:go_default_library",
|
||||
"//vendor/github.com/container-storage-interface/spec/lib/go/csi:go_default_library",
|
||||
"//vendor/google.golang.org/grpc:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
|
@ -58,6 +58,7 @@ go_test(
|
|||
"//pkg/volume/util:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/storage/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/storage/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
|
@ -71,8 +72,6 @@ go_test(
|
|||
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned/fake:go_default_library",
|
||||
"//vendor/github.com/container-storage-interface/spec/lib/go/csi:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
|
|
|
@ -37,7 +37,6 @@ import (
|
|||
fakeclient "k8s.io/client-go/kubernetes/fake"
|
||||
core "k8s.io/client-go/testing"
|
||||
utiltesting "k8s.io/client-go/util/testing"
|
||||
fakecsi "k8s.io/csi-api/pkg/client/clientset/versioned/fake"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
|
@ -236,12 +235,12 @@ func TestAttacherWithCSIDriver(t *testing.T) {
|
|||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
fakeCSIClient := fakecsi.NewSimpleClientset(
|
||||
fakeClient := fakeclient.NewSimpleClientset(
|
||||
getCSIDriver("not-attachable", nil, &bFalse),
|
||||
getCSIDriver("attachable", nil, &bTrue),
|
||||
getCSIDriver("nil", nil, nil),
|
||||
)
|
||||
plug, fakeWatcher, tmpDir, _ := newTestWatchPlugin(t, fakeCSIClient)
|
||||
plug, fakeWatcher, tmpDir, _ := newTestWatchPlugin(t, fakeClient)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
attacher, err := plug.NewAttacher()
|
||||
|
@ -274,10 +273,10 @@ func TestAttacherWithCSIDriver(t *testing.T) {
|
|||
t.Errorf("Attach() failed: %s", err)
|
||||
}
|
||||
if test.expectVolumeAttachment && attachID == "" {
|
||||
t.Errorf("Epected attachID, got nothing")
|
||||
t.Errorf("Expected attachID, got nothing")
|
||||
}
|
||||
if !test.expectVolumeAttachment && attachID != "" {
|
||||
t.Errorf("Epected empty attachID, got %q", attachID)
|
||||
t.Errorf("Expected empty attachID, got %q", attachID)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -318,12 +317,12 @@ func TestAttacherWaitForVolumeAttachmentWithCSIDriver(t *testing.T) {
|
|||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
fakeCSIClient := fakecsi.NewSimpleClientset(
|
||||
fakeClient := fakeclient.NewSimpleClientset(
|
||||
getCSIDriver("not-attachable", nil, &bFalse),
|
||||
getCSIDriver("attachable", nil, &bTrue),
|
||||
getCSIDriver("nil", nil, nil),
|
||||
)
|
||||
plug, tmpDir := newTestPlugin(t, nil, fakeCSIClient)
|
||||
plug, tmpDir := newTestPlugin(t, fakeClient)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
attacher, err := plug.NewAttacher()
|
||||
|
@ -519,7 +518,7 @@ func TestAttacherWaitForVolumeAttachment(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAttacherVolumesAreAttached(t *testing.T) {
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
attacher, err := plug.NewAttacher()
|
||||
|
@ -981,23 +980,20 @@ func TestAttacherUnmountDevice(t *testing.T) {
|
|||
}
|
||||
|
||||
// create a plugin mgr to load plugins and setup a fake client
|
||||
func newTestWatchPlugin(t *testing.T, csiClient *fakecsi.Clientset) (*csiPlugin, *watch.RaceFreeFakeWatcher, string, *fakeclient.Clientset) {
|
||||
func newTestWatchPlugin(t *testing.T, fakeClient *fakeclient.Clientset) (*csiPlugin, *watch.RaceFreeFakeWatcher, string, *fakeclient.Clientset) {
|
||||
tmpDir, err := utiltesting.MkTmpdir("csi-test")
|
||||
if err != nil {
|
||||
t.Fatalf("can't create temp dir: %v", err)
|
||||
}
|
||||
|
||||
fakeClient := fakeclient.NewSimpleClientset()
|
||||
fakeWatcher := watch.NewRaceFreeFake()
|
||||
fakeClient.Fake.PrependWatchReactor("*", core.DefaultWatchReactor(fakeWatcher, nil))
|
||||
fakeClient.Fake.WatchReactionChain = fakeClient.Fake.WatchReactionChain[:1]
|
||||
if csiClient == nil {
|
||||
csiClient = fakecsi.NewSimpleClientset()
|
||||
if fakeClient == nil {
|
||||
fakeClient = fakeclient.NewSimpleClientset()
|
||||
}
|
||||
fakeWatcher := watch.NewRaceFreeFake()
|
||||
fakeClient.Fake.AddWatchReactor("*", core.DefaultWatchReactor(fakeWatcher, nil))
|
||||
host := volumetest.NewFakeVolumeHostWithCSINodeName(
|
||||
tmpDir,
|
||||
fakeClient,
|
||||
csiClient,
|
||||
nil,
|
||||
"node",
|
||||
)
|
||||
|
|
|
@ -52,7 +52,7 @@ func prepareBlockMapperTest(plug *csiPlugin, specVolumeName string, t *testing.T
|
|||
func TestBlockMapperGetGlobalMapPath(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
// TODO (vladimirvivien) specName with slashes will not work
|
||||
|
@ -93,7 +93,7 @@ func TestBlockMapperGetGlobalMapPath(t *testing.T) {
|
|||
func TestBlockMapperGetStagingPath(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
testCases := []struct {
|
||||
|
@ -130,7 +130,7 @@ func TestBlockMapperGetStagingPath(t *testing.T) {
|
|||
func TestBlockMapperGetPublishPath(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
testCases := []struct {
|
||||
|
@ -167,7 +167,7 @@ func TestBlockMapperGetPublishPath(t *testing.T) {
|
|||
func TestBlockMapperGetDeviceMapPath(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
testCases := []struct {
|
||||
|
@ -208,14 +208,13 @@ func TestBlockMapperGetDeviceMapPath(t *testing.T) {
|
|||
func TestBlockMapperSetupDevice(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
fakeClient := fakeclient.NewSimpleClientset()
|
||||
host := volumetest.NewFakeVolumeHostWithCSINodeName(
|
||||
tmpDir,
|
||||
fakeClient,
|
||||
nil,
|
||||
nil,
|
||||
"fakeNode",
|
||||
)
|
||||
plug.host = host
|
||||
|
@ -275,14 +274,13 @@ func TestBlockMapperSetupDevice(t *testing.T) {
|
|||
func TestBlockMapperMapDevice(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
fakeClient := fakeclient.NewSimpleClientset()
|
||||
host := volumetest.NewFakeVolumeHostWithCSINodeName(
|
||||
tmpDir,
|
||||
fakeClient,
|
||||
nil,
|
||||
nil,
|
||||
"fakeNode",
|
||||
)
|
||||
plug.host = host
|
||||
|
@ -358,14 +356,13 @@ func TestBlockMapperMapDevice(t *testing.T) {
|
|||
func TestBlockMapperTearDownDevice(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
fakeClient := fakeclient.NewSimpleClientset()
|
||||
host := volumetest.NewFakeVolumeHostWithCSINodeName(
|
||||
tmpDir,
|
||||
fakeClient,
|
||||
nil,
|
||||
nil,
|
||||
"fakeNode",
|
||||
)
|
||||
plug.host = host
|
||||
|
|
|
@ -50,7 +50,6 @@ var (
|
|||
"nodeName",
|
||||
"attachmentID",
|
||||
}
|
||||
currentPodInfoMountVersion = "v1"
|
||||
)
|
||||
|
||||
type csiMountMgr struct {
|
||||
|
@ -247,8 +246,8 @@ func (c *csiMountMgr) podAttributes() (map[string]string, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// if PodInfoOnMountVersion is not set or not v1 we do not set pod attributes
|
||||
if csiDriver.Spec.PodInfoOnMountVersion == nil || *csiDriver.Spec.PodInfoOnMountVersion != currentPodInfoMountVersion {
|
||||
// if PodInfoOnMount is not set or false we do not set pod attributes
|
||||
if csiDriver.Spec.PodInfoOnMount == nil || *csiDriver.Spec.PodInfoOnMount == false {
|
||||
klog.V(4).Infof(log("CSIDriver %q does not require pod information", c.driverName))
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -29,14 +29,13 @@ import (
|
|||
|
||||
api "k8s.io/api/core/v1"
|
||||
storage "k8s.io/api/storage/v1"
|
||||
storagev1beta1 "k8s.io/api/storage/v1beta1"
|
||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
||||
fakeclient "k8s.io/client-go/kubernetes/fake"
|
||||
csiapi "k8s.io/csi-api/pkg/apis/csi/v1alpha1"
|
||||
fakecsi "k8s.io/csi-api/pkg/client/clientset/versioned/fake"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
|
@ -53,7 +52,7 @@ var (
|
|||
)
|
||||
|
||||
func TestMounterGetPath(t *testing.T) {
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
// TODO (vladimirvivien) specName with slashes will not work
|
||||
|
@ -142,17 +141,17 @@ func MounterSetUpTests(t *testing.T, podInfoEnabled bool) {
|
|||
},
|
||||
}
|
||||
|
||||
emptyPodMountInfoVersion := ""
|
||||
noPodMountInfo := false
|
||||
currentPodInfoMount := true
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
klog.Infof("Starting test %s", test.name)
|
||||
fakeClient := fakeclient.NewSimpleClientset()
|
||||
fakeCSIClient := fakecsi.NewSimpleClientset(
|
||||
getCSIDriver("no-info", &emptyPodMountInfoVersion, nil),
|
||||
getCSIDriver("info", ¤tPodInfoMountVersion, nil),
|
||||
fakeClient := fakeclient.NewSimpleClientset(
|
||||
getCSIDriver("no-info", &noPodMountInfo, nil),
|
||||
getCSIDriver("info", ¤tPodInfoMount, nil),
|
||||
getCSIDriver("nil", nil, nil),
|
||||
)
|
||||
plug, tmpDir := newTestPlugin(t, fakeClient, fakeCSIClient)
|
||||
plug, tmpDir := newTestPlugin(t, fakeClient)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) {
|
||||
|
@ -269,7 +268,7 @@ func TestMounterSetUp(t *testing.T) {
|
|||
}
|
||||
func TestMounterSetUpWithFSGroup(t *testing.T) {
|
||||
fakeClient := fakeclient.NewSimpleClientset()
|
||||
plug, tmpDir := newTestPlugin(t, fakeClient, nil)
|
||||
plug, tmpDir := newTestPlugin(t, fakeClient)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
testCases := []struct {
|
||||
|
@ -393,7 +392,7 @@ func TestMounterSetUpWithFSGroup(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUnmounterTeardown(t *testing.T) {
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
|
||||
pv := makeTestPV("test-pv", 10, testDriver, testVol)
|
||||
|
@ -443,7 +442,7 @@ func TestUnmounterTeardown(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSaveVolumeData(t *testing.T) {
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
@ -490,14 +489,14 @@ func TestSaveVolumeData(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func getCSIDriver(name string, podInfoMountVersion *string, attachable *bool) *csiapi.CSIDriver {
|
||||
return &csiapi.CSIDriver{
|
||||
func getCSIDriver(name string, podInfoMount *bool, attachable *bool) *storagev1beta1.CSIDriver {
|
||||
return &storagev1beta1.CSIDriver{
|
||||
ObjectMeta: meta.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
Spec: csiapi.CSIDriverSpec{
|
||||
PodInfoOnMountVersion: podInfoMountVersion,
|
||||
AttachRequired: attachable,
|
||||
Spec: storagev1beta1.CSIDriverSpec{
|
||||
PodInfoOnMount: podInfoMount,
|
||||
AttachRequired: attachable,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,10 +36,10 @@ import (
|
|||
utilversion "k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
csiapiinformer "k8s.io/client-go/informers"
|
||||
csiinformer "k8s.io/client-go/informers/storage/v1beta1"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
csiapiinformer "k8s.io/csi-api/pkg/client/informers/externalversions"
|
||||
csiinformer "k8s.io/csi-api/pkg/client/informers/externalversions/csi/v1alpha1"
|
||||
csilister "k8s.io/csi-api/pkg/client/listers/csi/v1alpha1"
|
||||
csilister "k8s.io/client-go/listers/storage/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
"k8s.io/kubernetes/pkg/volume/csi/nodeinfomanager"
|
||||
|
@ -205,16 +205,15 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error {
|
|||
p.host = host
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) {
|
||||
csiClient := host.GetCSIClient()
|
||||
csiClient := host.GetKubeClient()
|
||||
if csiClient == nil {
|
||||
klog.Warning("The client for CSI Custom Resources is not available, skipping informer initialization")
|
||||
} else {
|
||||
// Start informer for CSIDrivers.
|
||||
factory := csiapiinformer.NewSharedInformerFactory(csiClient, csiResyncPeriod)
|
||||
p.csiDriverInformer = factory.Csi().V1alpha1().CSIDrivers()
|
||||
p.csiDriverLister = p.csiDriverInformer.Lister()
|
||||
go factory.Start(wait.NeverStop)
|
||||
return errors.New("unable to get Kubernetes client")
|
||||
}
|
||||
// Start informer for CSIDrivers.
|
||||
factory := csiapiinformer.NewSharedInformerFactory(csiClient, csiResyncPeriod)
|
||||
p.csiDriverInformer = factory.Storage().V1beta1().CSIDrivers()
|
||||
p.csiDriverLister = p.csiDriverInformer.Lister()
|
||||
go factory.Start(wait.NeverStop)
|
||||
}
|
||||
|
||||
// Initializing the label management channels
|
||||
|
|
|
@ -32,14 +32,13 @@ import (
|
|||
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
||||
fakeclient "k8s.io/client-go/kubernetes/fake"
|
||||
utiltesting "k8s.io/client-go/util/testing"
|
||||
fakecsi "k8s.io/csi-api/pkg/client/clientset/versioned/fake"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
volumetest "k8s.io/kubernetes/pkg/volume/testing"
|
||||
)
|
||||
|
||||
// create a plugin mgr to load plugins and setup a fake client
|
||||
func newTestPlugin(t *testing.T, client *fakeclient.Clientset, csiClient *fakecsi.Clientset) (*csiPlugin, string) {
|
||||
func newTestPlugin(t *testing.T, client *fakeclient.Clientset) (*csiPlugin, string) {
|
||||
tmpDir, err := utiltesting.MkTmpdir("csi-test")
|
||||
if err != nil {
|
||||
t.Fatalf("can't create temp dir: %v", err)
|
||||
|
@ -48,13 +47,9 @@ func newTestPlugin(t *testing.T, client *fakeclient.Clientset, csiClient *fakecs
|
|||
if client == nil {
|
||||
client = fakeclient.NewSimpleClientset()
|
||||
}
|
||||
if csiClient == nil {
|
||||
csiClient = fakecsi.NewSimpleClientset()
|
||||
}
|
||||
host := volumetest.NewFakeVolumeHostWithCSINodeName(
|
||||
tmpDir,
|
||||
client,
|
||||
csiClient,
|
||||
nil,
|
||||
"fakeNode",
|
||||
)
|
||||
|
@ -120,7 +115,7 @@ func registerFakePlugin(pluginName, endpoint string, versions []string, t *testi
|
|||
func TestPluginGetPluginName(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
if plug.GetPluginName() != "kubernetes.io/csi" {
|
||||
t.Errorf("unexpected plugin name %v", plug.GetPluginName())
|
||||
|
@ -130,7 +125,7 @@ func TestPluginGetPluginName(t *testing.T) {
|
|||
func TestPluginGetVolumeName(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
@ -162,7 +157,7 @@ func TestPluginGetVolumeName(t *testing.T) {
|
|||
func TestPluginCanSupport(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
|
||||
|
@ -177,7 +172,7 @@ func TestPluginCanSupport(t *testing.T) {
|
|||
func TestPluginConstructVolumeSpec(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
testCases := []struct {
|
||||
|
@ -239,7 +234,7 @@ func TestPluginConstructVolumeSpec(t *testing.T) {
|
|||
func TestPluginNewMounter(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
registerFakePlugin(testDriver, "endpoint", []string{"1.2.0"}, t)
|
||||
|
@ -290,7 +285,7 @@ func TestPluginNewMounter(t *testing.T) {
|
|||
func TestPluginNewUnmounter(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
|
||||
|
@ -338,7 +333,7 @@ func TestPluginNewUnmounter(t *testing.T) {
|
|||
func TestPluginNewAttacher(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
attacher, err := plug.NewAttacher()
|
||||
|
@ -358,7 +353,7 @@ func TestPluginNewAttacher(t *testing.T) {
|
|||
func TestPluginNewDetacher(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
detacher, err := plug.NewDetacher()
|
||||
|
@ -389,10 +384,8 @@ func TestPluginCanAttach(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range tests {
|
||||
csiDriver := getCSIDriver(test.driverName, nil, &test.canAttach)
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
fakeCSIClient := fakecsi.NewSimpleClientset(csiDriver)
|
||||
plug, tmpDir := newTestPlugin(t, nil, fakeCSIClient)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
spec := volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, test.driverName, "test-vol"), false)
|
||||
|
||||
|
@ -408,7 +401,7 @@ func TestPluginCanAttach(t *testing.T) {
|
|||
func TestPluginNewBlockMapper(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
|
||||
|
@ -456,7 +449,7 @@ func TestPluginNewBlockMapper(t *testing.T) {
|
|||
func TestPluginNewUnmapper(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
|
||||
|
@ -516,7 +509,7 @@ func TestPluginNewUnmapper(t *testing.T) {
|
|||
func TestPluginConstructBlockVolumeSpec(t *testing.T) {
|
||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)()
|
||||
|
||||
plug, tmpDir := newTestPlugin(t, nil, nil)
|
||||
plug, tmpDir := newTestPlugin(t, nil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
testCases := []struct {
|
||||
|
|
|
@ -11,6 +11,7 @@ go_library(
|
|||
"//pkg/volume:go_default_library",
|
||||
"//pkg/volume/util:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/storage/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
|
@ -19,8 +20,7 @@ go_library(
|
|||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -50,6 +50,8 @@ go_test(
|
|||
"//pkg/volume/testing:go_default_library",
|
||||
"//pkg/volume/util:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/storage/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
|
@ -60,8 +62,6 @@ go_test(
|
|||
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned/fake:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -21,11 +21,11 @@ package nodeinfomanager // import "k8s.io/kubernetes/pkg/volume/csi/nodeinfomana
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
storage "k8s.io/api/storage/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@ -34,8 +34,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
csiv1alpha1 "k8s.io/csi-api/pkg/apis/csi/v1alpha1"
|
||||
csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
nodeutil "k8s.io/kubernetes/pkg/util/node"
|
||||
|
@ -59,7 +58,7 @@ var (
|
|||
)
|
||||
|
||||
// nodeInfoManager contains necessary common dependencies to update node info on both
|
||||
// the Node and CSINodeInfo objects.
|
||||
// the Node and CSINode objects.
|
||||
type nodeInfoManager struct {
|
||||
nodeName types.NodeName
|
||||
volumeHost volume.VolumeHost
|
||||
|
@ -70,7 +69,7 @@ type nodeUpdateFunc func(*v1.Node) (newNode *v1.Node, updated bool, err error)
|
|||
|
||||
// Interface implements an interface for managing labels of a node
|
||||
type Interface interface {
|
||||
CreateCSINodeInfo() (*csiv1alpha1.CSINodeInfo, error)
|
||||
CreateCSINode() (*storage.CSINode, error)
|
||||
|
||||
// Record in the cluster the given node information from the CSI driver with the given name.
|
||||
// Concurrent calls to InstallCSIDriver() is allowed, but they should not be intertwined with calls
|
||||
|
@ -94,9 +93,9 @@ func NewNodeInfoManager(
|
|||
}
|
||||
|
||||
// InstallCSIDriver updates the node ID annotation in the Node object and CSIDrivers field in the
|
||||
// CSINodeInfo object. If the CSINodeInfo object doesn't yet exist, it will be created.
|
||||
// CSINode object. If the CSINode object doesn't yet exist, it will be created.
|
||||
// If multiple calls to InstallCSIDriver() are made in parallel, some calls might receive Node or
|
||||
// CSINodeInfo update conflicts, which causes the function to retry the corresponding update.
|
||||
// CSINode update conflicts, which causes the function to retry the corresponding update.
|
||||
func (nim *nodeInfoManager) InstallCSIDriver(driverName string, driverNodeID string, maxAttachLimit int64, topology map[string]string) error {
|
||||
if driverNodeID == "" {
|
||||
return fmt.Errorf("error adding CSI driver node info: driverNodeID must not be empty")
|
||||
|
@ -120,23 +119,23 @@ func (nim *nodeInfoManager) InstallCSIDriver(driverName string, driverNodeID str
|
|||
}
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) {
|
||||
err = nim.updateCSINodeInfo(driverName, driverNodeID, topology)
|
||||
err = nim.updateCSINode(driverName, driverNodeID, topology)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error updating CSINodeInfo object with CSI driver node info: %v", err)
|
||||
return fmt.Errorf("error updating CSINode object with CSI driver node info: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UninstallCSIDriver removes the node ID annotation from the Node object and CSIDrivers field from the
|
||||
// CSINodeInfo object. If the CSINOdeInfo object contains no CSIDrivers, it will be deleted.
|
||||
// CSINode object. If the CSINOdeInfo object contains no CSIDrivers, it will be deleted.
|
||||
// If multiple calls to UninstallCSIDriver() are made in parallel, some calls might receive Node or
|
||||
// CSINodeInfo update conflicts, which causes the function to retry the corresponding update.
|
||||
// CSINode update conflicts, which causes the function to retry the corresponding update.
|
||||
func (nim *nodeInfoManager) UninstallCSIDriver(driverName string) error {
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) {
|
||||
err := nim.uninstallDriverFromCSINodeInfo(driverName)
|
||||
err := nim.uninstallDriverFromCSINode(driverName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error uninstalling CSI driver from CSINodeInfo object %v", err)
|
||||
return fmt.Errorf("error uninstalling CSI driver from CSINode object %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,55 +343,55 @@ func updateTopologyLabels(topology map[string]string) nodeUpdateFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func (nim *nodeInfoManager) updateCSINodeInfo(
|
||||
func (nim *nodeInfoManager) updateCSINode(
|
||||
driverName string,
|
||||
driverNodeID string,
|
||||
topology map[string]string) error {
|
||||
|
||||
csiKubeClient := nim.volumeHost.GetCSIClient()
|
||||
csiKubeClient := nim.volumeHost.GetKubeClient()
|
||||
if csiKubeClient == nil {
|
||||
return fmt.Errorf("error getting CSI client")
|
||||
}
|
||||
|
||||
var updateErrs []error
|
||||
err := wait.ExponentialBackoff(updateBackoff, func() (bool, error) {
|
||||
if err := nim.tryUpdateCSINodeInfo(csiKubeClient, driverName, driverNodeID, topology); err != nil {
|
||||
if err := nim.tryUpdateCSINode(csiKubeClient, driverName, driverNodeID, topology); err != nil {
|
||||
updateErrs = append(updateErrs, err)
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error updating CSINodeInfo: %v; caused by: %v", err, utilerrors.NewAggregate(updateErrs))
|
||||
return fmt.Errorf("error updating CSINode: %v; caused by: %v", err, utilerrors.NewAggregate(updateErrs))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nim *nodeInfoManager) tryUpdateCSINodeInfo(
|
||||
csiKubeClient csiclientset.Interface,
|
||||
func (nim *nodeInfoManager) tryUpdateCSINode(
|
||||
csiKubeClient clientset.Interface,
|
||||
driverName string,
|
||||
driverNodeID string,
|
||||
topology map[string]string) error {
|
||||
|
||||
nodeInfo, err := csiKubeClient.CsiV1alpha1().CSINodeInfos().Get(string(nim.nodeName), metav1.GetOptions{})
|
||||
nodeInfo, err := csiKubeClient.StorageV1beta1().CSINodes().Get(string(nim.nodeName), metav1.GetOptions{})
|
||||
if nodeInfo == nil || errors.IsNotFound(err) {
|
||||
nodeInfo, err = nim.CreateCSINodeInfo()
|
||||
nodeInfo, err = nim.CreateCSINode()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nim.installDriverToCSINodeInfo(nodeInfo, driverName, driverNodeID, topology)
|
||||
return nim.installDriverToCSINode(nodeInfo, driverName, driverNodeID, topology)
|
||||
}
|
||||
|
||||
func (nim *nodeInfoManager) CreateCSINodeInfo() (*csiv1alpha1.CSINodeInfo, error) {
|
||||
func (nim *nodeInfoManager) CreateCSINode() (*storage.CSINode, error) {
|
||||
|
||||
kubeClient := nim.volumeHost.GetKubeClient()
|
||||
if kubeClient == nil {
|
||||
return nil, fmt.Errorf("error getting kube client")
|
||||
}
|
||||
|
||||
csiKubeClient := nim.volumeHost.GetCSIClient()
|
||||
csiKubeClient := nim.volumeHost.GetKubeClient()
|
||||
if csiKubeClient == nil {
|
||||
return nil, fmt.Errorf("error getting CSI client")
|
||||
}
|
||||
|
@ -402,7 +401,7 @@ func (nim *nodeInfoManager) CreateCSINodeInfo() (*csiv1alpha1.CSINodeInfo, error
|
|||
return nil, err
|
||||
}
|
||||
|
||||
nodeInfo := &csiv1alpha1.CSINodeInfo{
|
||||
nodeInfo := &storage.CSINode{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: string(nim.nodeName),
|
||||
OwnerReferences: []metav1.OwnerReference{
|
||||
|
@ -414,24 +413,21 @@ func (nim *nodeInfoManager) CreateCSINodeInfo() (*csiv1alpha1.CSINodeInfo, error
|
|||
},
|
||||
},
|
||||
},
|
||||
Spec: csiv1alpha1.CSINodeInfoSpec{
|
||||
Drivers: []csiv1alpha1.CSIDriverInfoSpec{},
|
||||
},
|
||||
Status: csiv1alpha1.CSINodeInfoStatus{
|
||||
Drivers: []csiv1alpha1.CSIDriverInfoStatus{},
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{},
|
||||
},
|
||||
}
|
||||
|
||||
return csiKubeClient.CsiV1alpha1().CSINodeInfos().Create(nodeInfo)
|
||||
return csiKubeClient.StorageV1beta1().CSINodes().Create(nodeInfo)
|
||||
}
|
||||
|
||||
func (nim *nodeInfoManager) installDriverToCSINodeInfo(
|
||||
nodeInfo *csiv1alpha1.CSINodeInfo,
|
||||
func (nim *nodeInfoManager) installDriverToCSINode(
|
||||
nodeInfo *storage.CSINode,
|
||||
driverName string,
|
||||
driverNodeID string,
|
||||
topology map[string]string) error {
|
||||
|
||||
csiKubeClient := nim.volumeHost.GetCSIClient()
|
||||
csiKubeClient := nim.volumeHost.GetKubeClient()
|
||||
if csiKubeClient == nil {
|
||||
return fmt.Errorf("error getting CSI client")
|
||||
}
|
||||
|
@ -444,7 +440,7 @@ func (nim *nodeInfoManager) installDriverToCSINodeInfo(
|
|||
specModified := true
|
||||
statusModified := true
|
||||
// Clone driver list, omitting the driver that matches the given driverName
|
||||
newDriverSpecs := []csiv1alpha1.CSIDriverInfoSpec{}
|
||||
newDriverSpecs := []storage.CSINodeDriver{}
|
||||
for _, driverInfoSpec := range nodeInfo.Spec.Drivers {
|
||||
if driverInfoSpec.Name == driverName {
|
||||
if driverInfoSpec.NodeID == driverNodeID &&
|
||||
|
@ -456,106 +452,80 @@ func (nim *nodeInfoManager) installDriverToCSINodeInfo(
|
|||
newDriverSpecs = append(newDriverSpecs, driverInfoSpec)
|
||||
}
|
||||
}
|
||||
newDriverStatuses := []csiv1alpha1.CSIDriverInfoStatus{}
|
||||
for _, driverInfoStatus := range nodeInfo.Status.Drivers {
|
||||
if driverInfoStatus.Name == driverName {
|
||||
if driverInfoStatus.Available &&
|
||||
/* TODO(https://github.com/kubernetes/enhancements/issues/625): Add actual migration status */
|
||||
driverInfoStatus.VolumePluginMechanism == csiv1alpha1.VolumePluginMechanismInTree {
|
||||
statusModified = false
|
||||
}
|
||||
} else {
|
||||
// Omit driverInfoSpec matching given driverName
|
||||
newDriverStatuses = append(newDriverStatuses, driverInfoStatus)
|
||||
}
|
||||
}
|
||||
|
||||
if !specModified && !statusModified {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Append new driver
|
||||
driverSpec := csiv1alpha1.CSIDriverInfoSpec{
|
||||
driverSpec := storage.CSINodeDriver{
|
||||
Name: driverName,
|
||||
NodeID: driverNodeID,
|
||||
TopologyKeys: topologyKeys.List(),
|
||||
}
|
||||
driverStatus := csiv1alpha1.CSIDriverInfoStatus{
|
||||
Name: driverName,
|
||||
Available: true,
|
||||
// TODO(https://github.com/kubernetes/enhancements/issues/625): Add actual migration status
|
||||
VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree,
|
||||
}
|
||||
|
||||
newDriverSpecs = append(newDriverSpecs, driverSpec)
|
||||
newDriverStatuses = append(newDriverStatuses, driverStatus)
|
||||
nodeInfo.Spec.Drivers = newDriverSpecs
|
||||
nodeInfo.Status.Drivers = newDriverStatuses
|
||||
|
||||
err := validateCSINodeInfo(nodeInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = csiKubeClient.CsiV1alpha1().CSINodeInfos().Update(nodeInfo)
|
||||
_, err := csiKubeClient.StorageV1beta1().CSINodes().Update(nodeInfo)
|
||||
return err
|
||||
}
|
||||
|
||||
func (nim *nodeInfoManager) uninstallDriverFromCSINodeInfo(
|
||||
func (nim *nodeInfoManager) uninstallDriverFromCSINode(
|
||||
csiDriverName string) error {
|
||||
|
||||
csiKubeClient := nim.volumeHost.GetCSIClient()
|
||||
csiKubeClient := nim.volumeHost.GetKubeClient()
|
||||
if csiKubeClient == nil {
|
||||
return fmt.Errorf("error getting CSI client")
|
||||
}
|
||||
|
||||
var updateErrs []error
|
||||
err := wait.ExponentialBackoff(updateBackoff, func() (bool, error) {
|
||||
if err := nim.tryUninstallDriverFromCSINodeInfo(csiKubeClient, csiDriverName); err != nil {
|
||||
if err := nim.tryUninstallDriverFromCSINode(csiKubeClient, csiDriverName); err != nil {
|
||||
updateErrs = append(updateErrs, err)
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error updating CSINodeInfo: %v; caused by: %v", err, utilerrors.NewAggregate(updateErrs))
|
||||
return fmt.Errorf("error updating CSINode: %v; caused by: %v", err, utilerrors.NewAggregate(updateErrs))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nim *nodeInfoManager) tryUninstallDriverFromCSINodeInfo(
|
||||
csiKubeClient csiclientset.Interface,
|
||||
func (nim *nodeInfoManager) tryUninstallDriverFromCSINode(
|
||||
csiKubeClient clientset.Interface,
|
||||
csiDriverName string) error {
|
||||
|
||||
nodeInfoClient := csiKubeClient.CsiV1alpha1().CSINodeInfos()
|
||||
nodeInfoClient := csiKubeClient.StorageV1beta1().CSINodes()
|
||||
nodeInfo, err := nodeInfoClient.Get(string(nim.nodeName), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err // do not wrap error
|
||||
if err != nil && errors.IsNotFound(err) {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasModified := false
|
||||
newDriverStatuses := []csiv1alpha1.CSIDriverInfoStatus{}
|
||||
for _, driverStatus := range nodeInfo.Status.Drivers {
|
||||
if driverStatus.Name == csiDriverName {
|
||||
// Uninstall the driver if we find it
|
||||
hasModified = driverStatus.Available
|
||||
driverStatus.Available = false
|
||||
// Uninstall CSINodeDriver with name csiDriverName
|
||||
drivers := nodeInfo.Spec.Drivers[:0]
|
||||
for _, driver := range nodeInfo.Spec.Drivers {
|
||||
if driver.Name != csiDriverName {
|
||||
drivers = append(drivers, driver)
|
||||
} else {
|
||||
// Found a driver with name csiDriverName
|
||||
// Set hasModified to true because it will be removed
|
||||
hasModified = true
|
||||
}
|
||||
newDriverStatuses = append(newDriverStatuses, driverStatus)
|
||||
}
|
||||
|
||||
nodeInfo.Status.Drivers = newDriverStatuses
|
||||
|
||||
if !hasModified {
|
||||
// No changes, don't update
|
||||
return nil
|
||||
}
|
||||
nodeInfo.Spec.Drivers = drivers
|
||||
|
||||
err = validateCSINodeInfo(nodeInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, updateErr := nodeInfoClient.Update(nodeInfo)
|
||||
return updateErr // do not wrap error
|
||||
_, err = nodeInfoClient.Update(nodeInfo)
|
||||
|
||||
return err // do not wrap error
|
||||
|
||||
}
|
||||
|
||||
|
@ -611,50 +581,3 @@ func removeMaxAttachLimit(driverName string) nodeUpdateFunc {
|
|||
return node, true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// validateCSINodeInfo ensures members of CSINodeInfo object satisfies map and set semantics.
|
||||
// Before calling CSINodeInfoInterface.Update(), validateCSINodeInfo() should be invoked to
|
||||
// make sure the CSINodeInfo is compliant
|
||||
func validateCSINodeInfo(nodeInfo *csiv1alpha1.CSINodeInfo) error {
|
||||
if len(nodeInfo.Status.Drivers) < 1 {
|
||||
return fmt.Errorf("at least one Driver entry is required in driver statuses")
|
||||
}
|
||||
if len(nodeInfo.Spec.Drivers) < 1 {
|
||||
return fmt.Errorf("at least one Driver entry is required in driver specs")
|
||||
}
|
||||
if len(nodeInfo.Status.Drivers) != len(nodeInfo.Spec.Drivers) {
|
||||
return fmt.Errorf("")
|
||||
}
|
||||
// check for duplicate entries for the same driver in statuses
|
||||
var errors []string
|
||||
driverNamesInStatuses := make(sets.String)
|
||||
for _, driverInfo := range nodeInfo.Status.Drivers {
|
||||
if driverNamesInStatuses.Has(driverInfo.Name) {
|
||||
errors = append(errors, fmt.Sprintf("duplicate entries found for driver: %s in driver statuses", driverInfo.Name))
|
||||
}
|
||||
driverNamesInStatuses.Insert(driverInfo.Name)
|
||||
}
|
||||
// check for duplicate entries for the same driver in specs
|
||||
driverNamesInSpecs := make(sets.String)
|
||||
for _, driverInfo := range nodeInfo.Spec.Drivers {
|
||||
if driverNamesInSpecs.Has(driverInfo.Name) {
|
||||
errors = append(errors, fmt.Sprintf("duplicate entries found for driver: %s in driver specs", driverInfo.Name))
|
||||
}
|
||||
driverNamesInSpecs.Insert(driverInfo.Name)
|
||||
topoKeys := make(sets.String)
|
||||
for _, key := range driverInfo.TopologyKeys {
|
||||
if topoKeys.Has(key) {
|
||||
errors = append(errors, fmt.Sprintf("duplicate topology keys %s found for driver %s in driver specs", key, driverInfo.Name))
|
||||
}
|
||||
topoKeys.Insert(key)
|
||||
}
|
||||
}
|
||||
// check all entries in specs and status match
|
||||
if !driverNamesInSpecs.Equal(driverNamesInStatuses) {
|
||||
errors = append(errors, fmt.Sprintf("list of drivers in specs: %v does not match list of drivers in statuses: %v", driverNamesInSpecs.List(), driverNamesInStatuses.List()))
|
||||
}
|
||||
if len(errors) == 0 {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf(strings.Join(errors, ", "))
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -32,7 +32,6 @@ import (
|
|||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/record"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
"k8s.io/kubernetes/pkg/volume/util/recyclerclient"
|
||||
|
@ -318,9 +317,6 @@ type VolumeHost interface {
|
|||
// GetKubeClient returns a client interface
|
||||
GetKubeClient() clientset.Interface
|
||||
|
||||
// GetCSIClient returns a client interface to csi.storage.k8s.io
|
||||
GetCSIClient() csiclientset.Interface
|
||||
|
||||
// NewWrapperMounter finds an appropriate plugin with which to handle
|
||||
// the provided spec. This is used to implement volume plugins which
|
||||
// "wrap" other plugins. For example, the "secret" volume is
|
||||
|
|
|
@ -29,7 +29,6 @@ go_library(
|
|||
"//staging/src/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
|
||||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/mock:go_default_library",
|
||||
"//vendor/k8s.io/utils/strings:go_default_library",
|
||||
],
|
||||
|
|
|
@ -37,7 +37,6 @@ import (
|
|||
"k8s.io/client-go/tools/record"
|
||||
utiltesting "k8s.io/client-go/util/testing"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
. "k8s.io/kubernetes/pkg/volume"
|
||||
"k8s.io/kubernetes/pkg/volume/util"
|
||||
|
@ -65,7 +64,6 @@ const (
|
|||
type fakeVolumeHost struct {
|
||||
rootDir string
|
||||
kubeClient clientset.Interface
|
||||
csiClient csiclientset.Interface
|
||||
pluginMgr VolumePluginMgr
|
||||
cloud cloudprovider.Interface
|
||||
mounter mount.Interface
|
||||
|
@ -89,10 +87,9 @@ func NewFakeVolumeHostWithNodeLabels(rootDir string, kubeClient clientset.Interf
|
|||
return volHost
|
||||
}
|
||||
|
||||
func NewFakeVolumeHostWithCSINodeName(rootDir string, kubeClient clientset.Interface, csiClient csiclientset.Interface, plugins []VolumePlugin, nodeName string) *fakeVolumeHost {
|
||||
func NewFakeVolumeHostWithCSINodeName(rootDir string, kubeClient clientset.Interface, plugins []VolumePlugin, nodeName string) *fakeVolumeHost {
|
||||
volHost := newFakeVolumeHost(rootDir, kubeClient, plugins, nil, nil)
|
||||
volHost.nodeName = nodeName
|
||||
volHost.csiClient = csiClient
|
||||
return volHost
|
||||
}
|
||||
|
||||
|
@ -140,10 +137,6 @@ func (f *fakeVolumeHost) GetKubeClient() clientset.Interface {
|
|||
return f.kubeClient
|
||||
}
|
||||
|
||||
func (f *fakeVolumeHost) GetCSIClient() csiclientset.Interface {
|
||||
return f.csiClient
|
||||
}
|
||||
|
||||
func (f *fakeVolumeHost) GetCloudProvider() cloudprovider.Interface {
|
||||
return f.cloud
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ go_library(
|
|||
"//pkg/apis/coordination:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/policy:go_default_library",
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/auth/nodeidentifier:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/kubelet/apis:go_default_library",
|
||||
|
@ -30,7 +31,6 @@ go_library(
|
|||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/informers:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/listers/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -44,6 +44,7 @@ go_test(
|
|||
"//pkg/apis/coordination:go_default_library",
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/apis/policy:go_default_library",
|
||||
"//pkg/apis/storage:go_default_library",
|
||||
"//pkg/auth/nodeidentifier:go_default_library",
|
||||
"//pkg/features:go_default_library",
|
||||
"//pkg/kubelet/apis:go_default_library",
|
||||
|
@ -57,7 +58,6 @@ go_test(
|
|||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/listers/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/utils/pointer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -32,13 +32,13 @@ import (
|
|||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/client-go/informers"
|
||||
corev1lister "k8s.io/client-go/listers/core/v1"
|
||||
csiv1alpha1 "k8s.io/csi-api/pkg/apis/csi/v1alpha1"
|
||||
"k8s.io/klog"
|
||||
podutil "k8s.io/kubernetes/pkg/api/pod"
|
||||
authenticationapi "k8s.io/kubernetes/pkg/apis/authentication"
|
||||
coordapi "k8s.io/kubernetes/pkg/apis/coordination"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
storage "k8s.io/kubernetes/pkg/apis/storage"
|
||||
"k8s.io/kubernetes/pkg/auth/nodeidentifier"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||
|
@ -94,12 +94,12 @@ func (p *nodePlugin) ValidateInitialization() error {
|
|||
}
|
||||
|
||||
var (
|
||||
podResource = api.Resource("pods")
|
||||
nodeResource = api.Resource("nodes")
|
||||
pvcResource = api.Resource("persistentvolumeclaims")
|
||||
svcacctResource = api.Resource("serviceaccounts")
|
||||
leaseResource = coordapi.Resource("leases")
|
||||
csiNodeInfoResource = csiv1alpha1.Resource("csinodeinfos")
|
||||
podResource = api.Resource("pods")
|
||||
nodeResource = api.Resource("nodes")
|
||||
pvcResource = api.Resource("persistentvolumeclaims")
|
||||
svcacctResource = api.Resource("serviceaccounts")
|
||||
leaseResource = coordapi.Resource("leases")
|
||||
csiNodeResource = storage.Resource("csinodes")
|
||||
)
|
||||
|
||||
func (c *nodePlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||
|
@ -151,9 +151,9 @@ func (c *nodePlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces)
|
|||
}
|
||||
return admission.NewForbidden(a, fmt.Errorf("disabled by feature gate %s", features.NodeLease))
|
||||
|
||||
case csiNodeInfoResource:
|
||||
case csiNodeResource:
|
||||
if c.features.Enabled(features.KubeletPluginsWatcher) && c.features.Enabled(features.CSINodeInfo) {
|
||||
return c.admitCSINodeInfo(nodeName, a)
|
||||
return c.admitCSINode(nodeName, a)
|
||||
}
|
||||
return admission.NewForbidden(a, fmt.Errorf("disabled by feature gates %s and %s", features.KubeletPluginsWatcher, features.CSINodeInfo))
|
||||
|
||||
|
@ -530,8 +530,8 @@ func (r *nodePlugin) admitLease(nodeName string, a admission.Attributes) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *nodePlugin) admitCSINodeInfo(nodeName string, a admission.Attributes) error {
|
||||
// the request must come from a node with the same name as the CSINodeInfo object
|
||||
func (c *nodePlugin) admitCSINode(nodeName string, a admission.Attributes) error {
|
||||
// the request must come from a node with the same name as the CSINode object
|
||||
if a.GetOperation() == admission.Create {
|
||||
// a.GetName() won't return the name on create, so we drill down to the proposed object
|
||||
accessor, err := meta.Accessor(a.GetObject())
|
||||
|
@ -539,11 +539,11 @@ func (c *nodePlugin) admitCSINodeInfo(nodeName string, a admission.Attributes) e
|
|||
return admission.NewForbidden(a, fmt.Errorf("unable to access the object name"))
|
||||
}
|
||||
if accessor.GetName() != nodeName {
|
||||
return admission.NewForbidden(a, fmt.Errorf("can only access CSINodeInfo with the same name as the requesting node"))
|
||||
return admission.NewForbidden(a, fmt.Errorf("can only access CSINode with the same name as the requesting node"))
|
||||
}
|
||||
} else {
|
||||
if a.GetName() != nodeName {
|
||||
return admission.NewForbidden(a, fmt.Errorf("can only access CSINodeInfo with the same name as the requesting node"))
|
||||
return admission.NewForbidden(a, fmt.Errorf("can only access CSINode with the same name as the requesting node"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,11 +33,11 @@ import (
|
|||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
corev1lister "k8s.io/client-go/listers/core/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
csiv1alpha1 "k8s.io/csi-api/pkg/apis/csi/v1alpha1"
|
||||
authenticationapi "k8s.io/kubernetes/pkg/apis/authentication"
|
||||
"k8s.io/kubernetes/pkg/apis/coordination"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
storage "k8s.io/kubernetes/pkg/apis/storage"
|
||||
"k8s.io/kubernetes/pkg/auth/nodeidentifier"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||
|
@ -306,14 +306,14 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
csiNodeInfoResource = csiv1alpha1.Resource("csinodeinfos").WithVersion("v1alpha1")
|
||||
csiNodeInfoKind = schema.GroupVersionKind{Group: "csi.storage.k8s.io", Version: "v1alpha1", Kind: "CSINodeInfo"}
|
||||
nodeInfo = &csiv1alpha1.CSINodeInfo{
|
||||
csiNodeResource = storage.Resource("csinodes").WithVersion("v1beta1")
|
||||
csiNodeKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSINode"}
|
||||
nodeInfo = &storage.CSINode{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mynode",
|
||||
},
|
||||
Spec: csiv1alpha1.CSINodeInfoSpec{
|
||||
Drivers: []csiv1alpha1.CSIDriverInfoSpec{
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "com.example.csi/mydriver",
|
||||
NodeID: "com.example.csi/mynode",
|
||||
|
@ -321,22 +321,13 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
Status: csiv1alpha1.CSINodeInfoStatus{
|
||||
Drivers: []csiv1alpha1.CSIDriverInfoStatus{
|
||||
{
|
||||
Name: "com.example.csi/mydriver",
|
||||
Available: true,
|
||||
VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
nodeInfoWrongName = &csiv1alpha1.CSINodeInfo{
|
||||
nodeInfoWrongName = &storage.CSINode{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: csiv1alpha1.CSINodeInfoSpec{
|
||||
Drivers: []csiv1alpha1.CSIDriverInfoSpec{
|
||||
Spec: storage.CSINodeSpec{
|
||||
Drivers: []storage.CSINodeDriver{
|
||||
{
|
||||
Name: "com.example.csi/mydriver",
|
||||
NodeID: "com.example.csi/foo",
|
||||
|
@ -344,15 +335,6 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
Status: csiv1alpha1.CSINodeInfoStatus{
|
||||
Drivers: []csiv1alpha1.CSIDriverInfoStatus{
|
||||
{
|
||||
Name: "com.example.csi/mydriver",
|
||||
Available: true,
|
||||
VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
noExistingPodsIndex = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil)
|
||||
|
@ -1183,46 +1165,46 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
|||
features: leaseEnabledFeature,
|
||||
err: "",
|
||||
},
|
||||
// CSINodeInfo
|
||||
// CSINode
|
||||
{
|
||||
name: "disallowed create CSINodeInfo - feature disabled",
|
||||
attributes: admission.NewAttributesRecord(nodeInfo, nil, csiNodeInfoKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeInfoResource, "", admission.Create, false, mynode),
|
||||
name: "disallowed create CSINode - feature disabled",
|
||||
attributes: admission.NewAttributesRecord(nodeInfo, nil, csiNodeKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeResource, "", admission.Create, false, mynode),
|
||||
features: csiNodeInfoDisabledFeature,
|
||||
err: fmt.Sprintf("forbidden: disabled by feature gates %s and %s", features.KubeletPluginsWatcher, features.CSINodeInfo),
|
||||
},
|
||||
{
|
||||
name: "disallowed create another node's CSINodeInfo - feature enabled",
|
||||
attributes: admission.NewAttributesRecord(nodeInfoWrongName, nil, csiNodeInfoKind, nodeInfoWrongName.Namespace, nodeInfoWrongName.Name, csiNodeInfoResource, "", admission.Create, false, mynode),
|
||||
name: "disallowed create another node's CSINode - feature enabled",
|
||||
attributes: admission.NewAttributesRecord(nodeInfoWrongName, nil, csiNodeKind, nodeInfoWrongName.Namespace, nodeInfoWrongName.Name, csiNodeResource, "", admission.Create, false, mynode),
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
err: "forbidden: ",
|
||||
},
|
||||
{
|
||||
name: "disallowed update another node's CSINodeInfo - feature enabled",
|
||||
attributes: admission.NewAttributesRecord(nodeInfoWrongName, nodeInfoWrongName, csiNodeInfoKind, nodeInfoWrongName.Namespace, nodeInfoWrongName.Name, csiNodeInfoResource, "", admission.Update, false, mynode),
|
||||
name: "disallowed update another node's CSINode - feature enabled",
|
||||
attributes: admission.NewAttributesRecord(nodeInfoWrongName, nodeInfoWrongName, csiNodeKind, nodeInfoWrongName.Namespace, nodeInfoWrongName.Name, csiNodeResource, "", admission.Update, false, mynode),
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
err: "forbidden: ",
|
||||
},
|
||||
{
|
||||
name: "disallowed delete another node's CSINodeInfo - feature enabled",
|
||||
attributes: admission.NewAttributesRecord(nil, nil, csiNodeInfoKind, nodeInfoWrongName.Namespace, nodeInfoWrongName.Name, csiNodeInfoResource, "", admission.Delete, false, mynode),
|
||||
name: "disallowed delete another node's CSINode - feature enabled",
|
||||
attributes: admission.NewAttributesRecord(nil, nil, csiNodeKind, nodeInfoWrongName.Namespace, nodeInfoWrongName.Name, csiNodeResource, "", admission.Delete, false, mynode),
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
err: "forbidden: ",
|
||||
},
|
||||
{
|
||||
name: "allowed create node CSINodeInfo - feature enabled",
|
||||
attributes: admission.NewAttributesRecord(nodeInfo, nil, csiNodeInfoKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeInfoResource, "", admission.Create, false, mynode),
|
||||
name: "allowed create node CSINode - feature enabled",
|
||||
attributes: admission.NewAttributesRecord(nodeInfo, nil, csiNodeKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeResource, "", admission.Create, false, mynode),
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
err: "",
|
||||
},
|
||||
{
|
||||
name: "allowed update node CSINodeInfo - feature enabled",
|
||||
attributes: admission.NewAttributesRecord(nodeInfo, nodeInfo, csiNodeInfoKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeInfoResource, "", admission.Update, false, mynode),
|
||||
name: "allowed update node CSINode - feature enabled",
|
||||
attributes: admission.NewAttributesRecord(nodeInfo, nodeInfo, csiNodeKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeResource, "", admission.Update, false, mynode),
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
err: "",
|
||||
},
|
||||
{
|
||||
name: "allowed delete node CSINodeInfo - feature enabled",
|
||||
attributes: admission.NewAttributesRecord(nil, nil, csiNodeInfoKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeInfoResource, "", admission.Delete, false, mynode),
|
||||
name: "allowed delete node CSINode - feature enabled",
|
||||
attributes: admission.NewAttributesRecord(nil, nil, csiNodeKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeResource, "", admission.Delete, false, mynode),
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
err: "",
|
||||
},
|
||||
|
|
|
@ -56,7 +56,6 @@ go_library(
|
|||
"//staging/src/k8s.io/client-go/informers/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/informers/storage/v1:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
||||
"//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library",
|
||||
"//third_party/forked/gonum/graph:go_default_library",
|
||||
"//third_party/forked/gonum/graph/simple:go_default_library",
|
||||
"//third_party/forked/gonum/graph/traverse:go_default_library",
|
||||
|
|
|
@ -25,7 +25,6 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
csiv1alpha1 "k8s.io/csi-api/pkg/apis/csi/v1alpha1"
|
||||
coordapi "k8s.io/kubernetes/pkg/apis/coordination"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
storageapi "k8s.io/kubernetes/pkg/apis/storage"
|
||||
|
@ -68,14 +67,14 @@ func NewAuthorizer(graph *Graph, identifier nodeidentifier.NodeIdentifier, rules
|
|||
}
|
||||
|
||||
var (
|
||||
configMapResource = api.Resource("configmaps")
|
||||
secretResource = api.Resource("secrets")
|
||||
pvcResource = api.Resource("persistentvolumeclaims")
|
||||
pvResource = api.Resource("persistentvolumes")
|
||||
vaResource = storageapi.Resource("volumeattachments")
|
||||
svcAcctResource = api.Resource("serviceaccounts")
|
||||
leaseResource = coordapi.Resource("leases")
|
||||
csiNodeInfoResource = csiv1alpha1.Resource("csinodeinfos")
|
||||
configMapResource = api.Resource("configmaps")
|
||||
secretResource = api.Resource("secrets")
|
||||
pvcResource = api.Resource("persistentvolumeclaims")
|
||||
pvResource = api.Resource("persistentvolumes")
|
||||
vaResource = storageapi.Resource("volumeattachments")
|
||||
svcAcctResource = api.Resource("serviceaccounts")
|
||||
leaseResource = coordapi.Resource("leases")
|
||||
csiNodeResource = storageapi.Resource("csinodes")
|
||||
)
|
||||
|
||||
func (r *NodeAuthorizer) Authorize(attrs authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
|
@ -122,9 +121,9 @@ func (r *NodeAuthorizer) Authorize(attrs authorizer.Attributes) (authorizer.Deci
|
|||
return r.authorizeLease(nodeName, attrs)
|
||||
}
|
||||
return authorizer.DecisionNoOpinion, fmt.Sprintf("disabled by feature gate %s", features.NodeLease), nil
|
||||
case csiNodeInfoResource:
|
||||
case csiNodeResource:
|
||||
if r.features.Enabled(features.KubeletPluginsWatcher) && r.features.Enabled(features.CSINodeInfo) {
|
||||
return r.authorizeCSINodeInfo(nodeName, attrs)
|
||||
return r.authorizeCSINode(nodeName, attrs)
|
||||
}
|
||||
return authorizer.DecisionNoOpinion, fmt.Sprintf("disabled by feature gates %s and %s", features.KubeletPluginsWatcher, features.CSINodeInfo), nil
|
||||
}
|
||||
|
@ -260,8 +259,8 @@ func (r *NodeAuthorizer) authorizeLease(nodeName string, attrs authorizer.Attrib
|
|||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
|
||||
// authorizeCSINodeInfo authorizes node requests to CSINodeInfo csi.storage.k8s.io/csinodeinfos
|
||||
func (r *NodeAuthorizer) authorizeCSINodeInfo(nodeName string, attrs authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
// authorizeCSINode authorizes node requests to CSINode storage.k8s.io/csinodes
|
||||
func (r *NodeAuthorizer) authorizeCSINode(nodeName string, attrs authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
// allowed verbs: get, create, update, patch, delete
|
||||
verb := attrs.GetVerb()
|
||||
if verb != "get" &&
|
||||
|
@ -270,20 +269,20 @@ func (r *NodeAuthorizer) authorizeCSINodeInfo(nodeName string, attrs authorizer.
|
|||
verb != "patch" &&
|
||||
verb != "delete" {
|
||||
klog.V(2).Infof("NODE DENY: %s %#v", nodeName, attrs)
|
||||
return authorizer.DecisionNoOpinion, "can only get, create, update, patch, or delete a CSINodeInfo", nil
|
||||
return authorizer.DecisionNoOpinion, "can only get, create, update, patch, or delete a CSINode", nil
|
||||
}
|
||||
|
||||
if len(attrs.GetSubresource()) > 0 {
|
||||
klog.V(2).Infof("NODE DENY: %s %#v", nodeName, attrs)
|
||||
return authorizer.DecisionNoOpinion, "cannot authorize CSINodeInfo subresources", nil
|
||||
return authorizer.DecisionNoOpinion, "cannot authorize CSINode subresources", nil
|
||||
}
|
||||
|
||||
// the request must come from a node with the same name as the CSINodeInfo
|
||||
// the request must come from a node with the same name as the CSINode
|
||||
// note we skip this check for create, since the authorizer doesn't know the name on create
|
||||
// the noderestriction admission plugin is capable of performing this check at create time
|
||||
if verb != "create" && attrs.GetName() != nodeName {
|
||||
klog.V(2).Infof("NODE DENY: %s %#v", nodeName, attrs)
|
||||
return authorizer.DecisionNoOpinion, "can only access CSINodeInfo with the same name as the requesting node", nil
|
||||
return authorizer.DecisionNoOpinion, "can only access CSINode with the same name as the requesting node", nil
|
||||
}
|
||||
|
||||
return authorizer.DecisionAllow, "", nil
|
||||
|
|
|
@ -352,82 +352,82 @@ func TestAuthorizer(t *testing.T) {
|
|||
features: leaseEnabledFeature,
|
||||
expect: authorizer.DecisionAllow,
|
||||
},
|
||||
// CSINodeInfo
|
||||
// CSINode
|
||||
{
|
||||
name: "disallowed CSINodeInfo - feature disabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node0"},
|
||||
name: "disallowed CSINode - feature disabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node0"},
|
||||
features: csiNodeInfoDisabledFeature,
|
||||
expect: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
name: "disallowed CSINodeInfo with subresource - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodeinfos", Subresource: "csiDrivers", APIGroup: "csi.storage.k8s.io", Name: "node0"},
|
||||
name: "disallowed CSINode with subresource - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodes", Subresource: "csiDrivers", APIGroup: "storage.k8s.io", Name: "node0"},
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
expect: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
name: "disallowed get another node's CSINodeInfo - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node1"},
|
||||
name: "disallowed get another node's CSINode - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node1"},
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
expect: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
name: "disallowed update another node's CSINodeInfo - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "update", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node1"},
|
||||
name: "disallowed update another node's CSINode - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "update", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node1"},
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
expect: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
name: "disallowed patch another node's CSINodeInfo - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "patch", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node1"},
|
||||
name: "disallowed patch another node's CSINode - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "patch", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node1"},
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
expect: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
name: "disallowed delete another node's CSINodeInfo - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "delete", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node1"},
|
||||
name: "disallowed delete another node's CSINode - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "delete", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node1"},
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
expect: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
name: "disallowed list CSINodeInfos - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "list", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io"},
|
||||
name: "disallowed list CSINodes - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "list", Resource: "csinodes", APIGroup: "storage.k8s.io"},
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
expect: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
name: "disallowed watch CSINodeInfos - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "watch", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io"},
|
||||
name: "disallowed watch CSINodes - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "watch", Resource: "csinodes", APIGroup: "storage.k8s.io"},
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
expect: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
name: "allowed get CSINodeInfo - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node0"},
|
||||
name: "allowed get CSINode - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node0"},
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
expect: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
name: "allowed create CSINodeInfo - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "create", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node0"},
|
||||
name: "allowed create CSINode - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "create", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node0"},
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
expect: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
name: "allowed update CSINodeInfo - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "update", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node0"},
|
||||
name: "allowed update CSINode - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "update", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node0"},
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
expect: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
name: "allowed patch CSINodeInfo - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "patch", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node0"},
|
||||
name: "allowed patch CSINode - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "patch", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node0"},
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
expect: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
name: "allowed delete CSINodeInfo - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "delete", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node0"},
|
||||
name: "allowed delete CSINode - feature enabled",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "delete", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node0"},
|
||||
features: csiNodeInfoEnabledFeature,
|
||||
expect: authorizer.DecisionAllow,
|
||||
},
|
||||
|
|
|
@ -74,7 +74,7 @@ func buildControllerRoles() ([]rbacv1.ClusterRole, []rbacv1.ClusterRoleBinding)
|
|||
if utilfeature.DefaultFeatureGate.Enabled(features.CSIPersistentVolume) {
|
||||
role.Rules = append(role.Rules, rbacv1helpers.NewRule("get", "create", "delete", "list", "watch").Groups(storageGroup).Resources("volumeattachments").RuleOrDie())
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) {
|
||||
role.Rules = append(role.Rules, rbacv1helpers.NewRule("get", "watch", "list").Groups("csi.storage.k8s.io").Resources("csidrivers").RuleOrDie())
|
||||
role.Rules = append(role.Rules, rbacv1helpers.NewRule("get", "watch", "list").Groups("storage.k8s.io").Resources("csidrivers").RuleOrDie())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -160,13 +160,13 @@ func NodeRules() []rbacv1.PolicyRule {
|
|||
volAttachRule := rbacv1helpers.NewRule("get").Groups(storageGroup).Resources("volumeattachments").RuleOrDie()
|
||||
nodePolicyRules = append(nodePolicyRules, volAttachRule)
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) {
|
||||
csiDriverRule := rbacv1helpers.NewRule("get", "watch", "list").Groups("csi.storage.k8s.io").Resources("csidrivers").RuleOrDie()
|
||||
csiDriverRule := rbacv1helpers.NewRule("get", "watch", "list").Groups("storage.k8s.io").Resources("csidrivers").RuleOrDie()
|
||||
nodePolicyRules = append(nodePolicyRules, csiDriverRule)
|
||||
}
|
||||
}
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.KubeletPluginsWatcher) &&
|
||||
utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) {
|
||||
csiNodeInfoRule := rbacv1helpers.NewRule("get", "create", "update", "patch", "delete").Groups("csi.storage.k8s.io").Resources("csinodeinfos").RuleOrDie()
|
||||
csiNodeInfoRule := rbacv1helpers.NewRule("get", "create", "update", "patch", "delete").Groups("storage.k8s.io").Resources("csinodes").RuleOrDie()
|
||||
nodePolicyRules = append(nodePolicyRules, csiNodeInfoRule)
|
||||
}
|
||||
|
||||
|
@ -514,7 +514,7 @@ func ClusterRoles() []rbacv1.ClusterRole {
|
|||
rbacv1helpers.NewRule("get", "list", "watch").Groups(legacyGroup).Resources("nodes").RuleOrDie(),
|
||||
}
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) {
|
||||
externalProvisionerRules = append(externalProvisionerRules, rbacv1helpers.NewRule("get", "watch", "list").Groups("csi.storage.k8s.io").Resources("csinodeinfos").RuleOrDie())
|
||||
externalProvisionerRules = append(externalProvisionerRules, rbacv1helpers.NewRule("get", "watch", "list").Groups("storage.k8s.io").Resources("csinodes").RuleOrDie())
|
||||
}
|
||||
roles = append(roles, rbacv1.ClusterRole{
|
||||
// a role for the csi external provisioner
|
||||
|
|
|
@ -534,6 +534,14 @@ items:
|
|||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- storage.k8s.io
|
||||
resources:
|
||||
- csinodes
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
|
@ -987,6 +995,24 @@ items:
|
|||
- volumeattachments
|
||||
verbs:
|
||||
- get
|
||||
- apiGroups:
|
||||
- storage.k8s.io
|
||||
resources:
|
||||
- csidrivers
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- storage.k8s.io
|
||||
resources:
|
||||
- csinodes
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- coordination.k8s.io
|
||||
resources:
|
||||
|
|
|
@ -58,6 +58,14 @@ items:
|
|||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- storage.k8s.io
|
||||
resources:
|
||||
- csidrivers
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -29,6 +29,143 @@ import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
|
|||
// Package-wide variables from generator "generated".
|
||||
option go_package = "v1beta1";
|
||||
|
||||
// CSIDriver captures information about a Container Storage Interface (CSI)
|
||||
// volume driver deployed on the cluster.
|
||||
// CSI drivers do not need to create the CSIDriver object directly. Instead they may use the
|
||||
// cluster-driver-registrar sidecar container. When deployed with a CSI driver it automatically
|
||||
// creates a CSIDriver object representing the driver.
|
||||
// Kubernetes attach detach controller uses this object to determine whether attach is required.
|
||||
// Kubelet uses this object to determine whether pod information needs to be passed on mount.
|
||||
// CSIDriver objects are non-namespaced.
|
||||
message CSIDriver {
|
||||
// Standard object metadata.
|
||||
// metadata.Name indicates the name of the CSI driver that this object
|
||||
// refers to; it MUST be the same name returned by the CSI GetPluginName()
|
||||
// call for that driver.
|
||||
// The driver name must be 63 characters or less, beginning and ending with
|
||||
// an alphanumeric character ([a-z0-9A-Z]) with dashes (-), dots (.), and
|
||||
// alphanumerics between.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||
|
||||
// Specification of the CSI Driver.
|
||||
optional CSIDriverSpec spec = 2;
|
||||
}
|
||||
|
||||
// CSIDriverList is a collection of CSIDriver objects.
|
||||
message CSIDriverList {
|
||||
// Standard list metadata
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
|
||||
// +optional
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1;
|
||||
|
||||
// items is the list of CSIDriver
|
||||
repeated CSIDriver items = 2;
|
||||
}
|
||||
|
||||
// CSIDriverSpec is the specification of a CSIDriver.
|
||||
message CSIDriverSpec {
|
||||
// attachRequired indicates this CSI volume driver requires an attach
|
||||
// operation (because it implements the CSI ControllerPublishVolume()
|
||||
// method), and that the Kubernetes attach detach controller should call
|
||||
// the attach volume interface which checks the volumeattachment status
|
||||
// and waits until the volume is attached before proceeding to mounting.
|
||||
// The CSI external-attacher coordinates with CSI volume driver and updates
|
||||
// the volumeattachment status when the attach operation is complete.
|
||||
// If the CSIDriverRegistry feature gate is enabled and the value is
|
||||
// specified to false, the attach operation will be skipped.
|
||||
// Otherwise the attach operation will be called.
|
||||
// +optional
|
||||
optional bool attachRequired = 1;
|
||||
|
||||
// If set to true, podInfoOnMount indicates this CSI volume driver
|
||||
// requires additional pod information (like podName, podUID, etc.) during
|
||||
// mount operations.
|
||||
// If set to false, pod information will not be passed on mount.
|
||||
// Default is false.
|
||||
// The CSI driver specifies podInfoOnMount as part of driver deployment.
|
||||
// If true, Kubelet will pass pod information as VolumeContext in the CSI
|
||||
// NodePublishVolume() calls.
|
||||
// The CSI driver is responsible for parsing and validating the information
|
||||
// passed in as VolumeContext.
|
||||
// The following VolumeConext will be passed if podInfoOnMount is set to true.
|
||||
// This list might grow, but the prefix will be used.
|
||||
// "csi.storage.k8s.io/pod.name": pod.Name
|
||||
// "csi.storage.k8s.io/pod.namespace": pod.Namespace
|
||||
// "csi.storage.k8s.io/pod.uid": string(pod.UID)
|
||||
// +optional
|
||||
optional bool podInfoOnMount = 2;
|
||||
}
|
||||
|
||||
// CSINode holds information about all CSI drivers installed on a node.
|
||||
// CSI drivers do not need to create the CSINode object directly. As long as
|
||||
// they use the node-driver-registrar sidecar container, the kubelet will
|
||||
// automatically populate the CSINode object for the CSI driver as part of
|
||||
// kubelet plugin registration.
|
||||
// CSINode has the same name as a node. If the object is missing, it means either
|
||||
// there are no CSI Drivers available on the node, or the Kubelet version is low
|
||||
// enough that it doesn't create this object.
|
||||
// CSINode has an OwnerReference that points to the corresponding node object.
|
||||
message CSINode {
|
||||
// metadata.name must be the Kubernetes node name.
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||
|
||||
// spec is the specification of CSINode
|
||||
optional CSINodeSpec spec = 2;
|
||||
}
|
||||
|
||||
// CSINodeDriver holds information about the specification of one CSI driver installed on a node
|
||||
message CSINodeDriver {
|
||||
// This is the name of the CSI driver that this object refers to.
|
||||
// This MUST be the same name returned by the CSI GetPluginName() call for
|
||||
// that driver.
|
||||
optional string name = 1;
|
||||
|
||||
// nodeID of the node from the driver point of view.
|
||||
// This field enables Kubernetes to communicate with storage systems that do
|
||||
// not share the same nomenclature for nodes. For example, Kubernetes may
|
||||
// refer to a given node as "node1", but the storage system may refer to
|
||||
// the same node as "nodeA". When Kubernetes issues a command to the storage
|
||||
// system to attach a volume to a specific node, it can use this field to
|
||||
// refer to the node name using the ID that the storage system will
|
||||
// understand, e.g. "nodeA" instead of "node1". This field is required.
|
||||
optional string nodeID = 2;
|
||||
|
||||
// topologyKeys is the list of keys supported by the driver.
|
||||
// When a driver is initialized on a cluster, it provides a set of topology
|
||||
// keys that it understands (e.g. "company.com/zone", "company.com/region").
|
||||
// When a driver is initialized on a node, it provides the same topology keys
|
||||
// along with values. Kubelet will expose these topology keys as labels
|
||||
// on its own node object.
|
||||
// When Kubernetes does topology aware provisioning, it can use this list to
|
||||
// determine which labels it should retrieve from the node object and pass
|
||||
// back to the driver.
|
||||
// It is possible for different nodes to use different topology keys.
|
||||
// This can be empty if driver does not support topology.
|
||||
// +optional
|
||||
repeated string topologyKeys = 3;
|
||||
}
|
||||
|
||||
// CSINodeList is a collection of CSINode objects.
|
||||
message CSINodeList {
|
||||
// Standard list metadata
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
|
||||
// +optional
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1;
|
||||
|
||||
// items is the list of CSINode
|
||||
repeated CSINode items = 2;
|
||||
}
|
||||
|
||||
// CSINodeSpec holds information about the specification of all CSI drivers installed on a node
|
||||
message CSINodeSpec {
|
||||
// drivers is a list of information of all CSI Drivers existing on a node.
|
||||
// If all drivers in the list are uninstalled, this can become empty.
|
||||
// +patchMergeKey=name
|
||||
// +patchStrategy=merge
|
||||
repeated CSINodeDriver drivers = 1;
|
||||
}
|
||||
|
||||
// StorageClass describes the parameters for a class of storage for
|
||||
// which PersistentVolumes can be dynamically provisioned.
|
||||
//
|
||||
|
|
|
@ -49,6 +49,12 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
|||
|
||||
&VolumeAttachment{},
|
||||
&VolumeAttachmentList{},
|
||||
|
||||
&CSIDriver{},
|
||||
&CSIDriverList{},
|
||||
|
||||
&CSINode{},
|
||||
&CSINodeList{},
|
||||
)
|
||||
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
|
|
|
@ -209,3 +209,160 @@ type VolumeError struct {
|
|||
// +optional
|
||||
Message string `json:"message,omitempty" protobuf:"bytes,2,opt,name=message"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:nonNamespaced
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// CSIDriver captures information about a Container Storage Interface (CSI)
|
||||
// volume driver deployed on the cluster.
|
||||
// CSI drivers do not need to create the CSIDriver object directly. Instead they may use the
|
||||
// cluster-driver-registrar sidecar container. When deployed with a CSI driver it automatically
|
||||
// creates a CSIDriver object representing the driver.
|
||||
// Kubernetes attach detach controller uses this object to determine whether attach is required.
|
||||
// Kubelet uses this object to determine whether pod information needs to be passed on mount.
|
||||
// CSIDriver objects are non-namespaced.
|
||||
type CSIDriver struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Standard object metadata.
|
||||
// metadata.Name indicates the name of the CSI driver that this object
|
||||
// refers to; it MUST be the same name returned by the CSI GetPluginName()
|
||||
// call for that driver.
|
||||
// The driver name must be 63 characters or less, beginning and ending with
|
||||
// an alphanumeric character ([a-z0-9A-Z]) with dashes (-), dots (.), and
|
||||
// alphanumerics between.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Specification of the CSI Driver.
|
||||
Spec CSIDriverSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// CSIDriverList is a collection of CSIDriver objects.
|
||||
type CSIDriverList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Standard list metadata
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
|
||||
// +optional
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// items is the list of CSIDriver
|
||||
Items []CSIDriver `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// CSIDriverSpec is the specification of a CSIDriver.
|
||||
type CSIDriverSpec struct {
|
||||
// attachRequired indicates this CSI volume driver requires an attach
|
||||
// operation (because it implements the CSI ControllerPublishVolume()
|
||||
// method), and that the Kubernetes attach detach controller should call
|
||||
// the attach volume interface which checks the volumeattachment status
|
||||
// and waits until the volume is attached before proceeding to mounting.
|
||||
// The CSI external-attacher coordinates with CSI volume driver and updates
|
||||
// the volumeattachment status when the attach operation is complete.
|
||||
// If the CSIDriverRegistry feature gate is enabled and the value is
|
||||
// specified to false, the attach operation will be skipped.
|
||||
// Otherwise the attach operation will be called.
|
||||
// +optional
|
||||
AttachRequired *bool `json:"attachRequired,omitempty" protobuf:"varint,1,opt,name=attachRequired"`
|
||||
|
||||
// If set to true, podInfoOnMount indicates this CSI volume driver
|
||||
// requires additional pod information (like podName, podUID, etc.) during
|
||||
// mount operations.
|
||||
// If set to false, pod information will not be passed on mount.
|
||||
// Default is false.
|
||||
// The CSI driver specifies podInfoOnMount as part of driver deployment.
|
||||
// If true, Kubelet will pass pod information as VolumeContext in the CSI
|
||||
// NodePublishVolume() calls.
|
||||
// The CSI driver is responsible for parsing and validating the information
|
||||
// passed in as VolumeContext.
|
||||
// The following VolumeConext will be passed if podInfoOnMount is set to true.
|
||||
// This list might grow, but the prefix will be used.
|
||||
// "csi.storage.k8s.io/pod.name": pod.Name
|
||||
// "csi.storage.k8s.io/pod.namespace": pod.Namespace
|
||||
// "csi.storage.k8s.io/pod.uid": string(pod.UID)
|
||||
// +optional
|
||||
PodInfoOnMount *bool `json:"podInfoOnMount,omitempty" protobuf:"bytes,2,opt,name=podInfoOnMount"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:nonNamespaced
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// CSINode holds information about all CSI drivers installed on a node.
|
||||
// CSI drivers do not need to create the CSINode object directly. As long as
|
||||
// they use the node-driver-registrar sidecar container, the kubelet will
|
||||
// automatically populate the CSINode object for the CSI driver as part of
|
||||
// kubelet plugin registration.
|
||||
// CSINode has the same name as a node. If the object is missing, it means either
|
||||
// there are no CSI Drivers available on the node, or the Kubelet version is low
|
||||
// enough that it doesn't create this object.
|
||||
// CSINode has an OwnerReference that points to the corresponding node object.
|
||||
type CSINode struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// metadata.name must be the Kubernetes node name.
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// spec is the specification of CSINode
|
||||
Spec CSINodeSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
|
||||
}
|
||||
|
||||
// CSINodeSpec holds information about the specification of all CSI drivers installed on a node
|
||||
type CSINodeSpec struct {
|
||||
// drivers is a list of information of all CSI Drivers existing on a node.
|
||||
// If all drivers in the list are uninstalled, this can become empty.
|
||||
// +patchMergeKey=name
|
||||
// +patchStrategy=merge
|
||||
Drivers []CSINodeDriver `json:"drivers" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,1,rep,name=drivers"`
|
||||
}
|
||||
|
||||
// CSINodeDriver holds information about the specification of one CSI driver installed on a node
|
||||
type CSINodeDriver struct {
|
||||
// This is the name of the CSI driver that this object refers to.
|
||||
// This MUST be the same name returned by the CSI GetPluginName() call for
|
||||
// that driver.
|
||||
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
|
||||
|
||||
// nodeID of the node from the driver point of view.
|
||||
// This field enables Kubernetes to communicate with storage systems that do
|
||||
// not share the same nomenclature for nodes. For example, Kubernetes may
|
||||
// refer to a given node as "node1", but the storage system may refer to
|
||||
// the same node as "nodeA". When Kubernetes issues a command to the storage
|
||||
// system to attach a volume to a specific node, it can use this field to
|
||||
// refer to the node name using the ID that the storage system will
|
||||
// understand, e.g. "nodeA" instead of "node1". This field is required.
|
||||
NodeID string `json:"nodeID" protobuf:"bytes,2,opt,name=nodeID"`
|
||||
|
||||
// topologyKeys is the list of keys supported by the driver.
|
||||
// When a driver is initialized on a cluster, it provides a set of topology
|
||||
// keys that it understands (e.g. "company.com/zone", "company.com/region").
|
||||
// When a driver is initialized on a node, it provides the same topology keys
|
||||
// along with values. Kubelet will expose these topology keys as labels
|
||||
// on its own node object.
|
||||
// When Kubernetes does topology aware provisioning, it can use this list to
|
||||
// determine which labels it should retrieve from the node object and pass
|
||||
// back to the driver.
|
||||
// It is possible for different nodes to use different topology keys.
|
||||
// This can be empty if driver does not support topology.
|
||||
// +optional
|
||||
TopologyKeys []string `json:"topologyKeys" protobuf:"bytes,3,rep,name=topologyKeys"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// CSINodeList is a collection of CSINode objects.
|
||||
type CSINodeList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// Standard list metadata
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
|
||||
// +optional
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// items is the list of CSINode
|
||||
Items []CSINode `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
|
|
@ -27,6 +27,76 @@ package v1beta1
|
|||
// Those methods can be generated by using hack/update-generated-swagger-docs.sh
|
||||
|
||||
// AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT.
|
||||
var map_CSIDriver = map[string]string{
|
||||
"": "CSIDriver captures information about a Container Storage Interface (CSI) volume driver deployed on the cluster. CSI drivers do not need to create the CSIDriver object directly. Instead they may use the cluster-driver-registrar sidecar container. When deployed with a CSI driver it automatically creates a CSIDriver object representing the driver. Kubernetes attach detach controller uses this object to determine whether attach is required. Kubelet uses this object to determine whether pod information needs to be passed on mount. CSIDriver objects are non-namespaced.",
|
||||
"metadata": "Standard object metadata. metadata.Name indicates the name of the CSI driver that this object refers to; it MUST be the same name returned by the CSI GetPluginName() call for that driver. The driver name must be 63 characters or less, beginning and ending with an alphanumeric character ([a-z0-9A-Z]) with dashes (-), dots (.), and alphanumerics between. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata",
|
||||
"spec": "Specification of the CSI Driver.",
|
||||
}
|
||||
|
||||
func (CSIDriver) SwaggerDoc() map[string]string {
|
||||
return map_CSIDriver
|
||||
}
|
||||
|
||||
var map_CSIDriverList = map[string]string{
|
||||
"": "CSIDriverList is a collection of CSIDriver objects.",
|
||||
"metadata": "Standard list metadata More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata",
|
||||
"items": "items is the list of CSIDriver",
|
||||
}
|
||||
|
||||
func (CSIDriverList) SwaggerDoc() map[string]string {
|
||||
return map_CSIDriverList
|
||||
}
|
||||
|
||||
var map_CSIDriverSpec = map[string]string{
|
||||
"": "CSIDriverSpec is the specification of a CSIDriver.",
|
||||
"attachRequired": "attachRequired indicates this CSI volume driver requires an attach operation (because it implements the CSI ControllerPublishVolume() method), and that the Kubernetes attach detach controller should call the attach volume interface which checks the volumeattachment status and waits until the volume is attached before proceeding to mounting. The CSI external-attacher coordinates with CSI volume driver and updates the volumeattachment status when the attach operation is complete. If the CSIDriverRegistry feature gate is enabled and the value is specified to false, the attach operation will be skipped. Otherwise the attach operation will be called.",
|
||||
"podInfoOnMount": "If set to true, podInfoOnMount indicates this CSI volume driver requires additional pod information (like podName, podUID, etc.) during mount operations. If set to false, pod information will not be passed on mount. Default is false. The CSI driver specifies podInfoOnMount as part of driver deployment. If true, Kubelet will pass pod information as VolumeContext in the CSI NodePublishVolume() calls. The CSI driver is responsible for parsing and validating the information passed in as VolumeContext. The following VolumeConext will be passed if podInfoOnMount is set to true. This list might grow, but the prefix will be used. \"csi.storage.k8s.io/pod.name\": pod.Name \"csi.storage.k8s.io/pod.namespace\": pod.Namespace \"csi.storage.k8s.io/pod.uid\": string(pod.UID)",
|
||||
}
|
||||
|
||||
func (CSIDriverSpec) SwaggerDoc() map[string]string {
|
||||
return map_CSIDriverSpec
|
||||
}
|
||||
|
||||
var map_CSINode = map[string]string{
|
||||
"": "CSINode holds information about all CSI drivers installed on a node. CSI drivers do not need to create the CSINode object directly. As long as they use the node-driver-registrar sidecar container, the kubelet will automatically populate the CSINode object for the CSI driver as part of kubelet plugin registration. CSINode has the same name as a node. If the object is missing, it means either there are no CSI Drivers available on the node, or the Kubelet version is low enough that it doesn't create this object. CSINode has an OwnerReference that points to the corresponding node object.",
|
||||
"metadata": "metadata.name must be the Kubernetes node name.",
|
||||
"spec": "spec is the specification of CSINode",
|
||||
}
|
||||
|
||||
func (CSINode) SwaggerDoc() map[string]string {
|
||||
return map_CSINode
|
||||
}
|
||||
|
||||
var map_CSINodeDriver = map[string]string{
|
||||
"": "CSINodeDriver holds information about the specification of one CSI driver installed on a node",
|
||||
"name": "This is the name of the CSI driver that this object refers to. This MUST be the same name returned by the CSI GetPluginName() call for that driver.",
|
||||
"nodeID": "nodeID of the node from the driver point of view. This field enables Kubernetes to communicate with storage systems that do not share the same nomenclature for nodes. For example, Kubernetes may refer to a given node as \"node1\", but the storage system may refer to the same node as \"nodeA\". When Kubernetes issues a command to the storage system to attach a volume to a specific node, it can use this field to refer to the node name using the ID that the storage system will understand, e.g. \"nodeA\" instead of \"node1\". This field is required.",
|
||||
"topologyKeys": "topologyKeys is the list of keys supported by the driver. When a driver is initialized on a cluster, it provides a set of topology keys that it understands (e.g. \"company.com/zone\", \"company.com/region\"). When a driver is initialized on a node, it provides the same topology keys along with values. Kubelet will expose these topology keys as labels on its own node object. When Kubernetes does topology aware provisioning, it can use this list to determine which labels it should retrieve from the node object and pass back to the driver. It is possible for different nodes to use different topology keys. This can be empty if driver does not support topology.",
|
||||
}
|
||||
|
||||
func (CSINodeDriver) SwaggerDoc() map[string]string {
|
||||
return map_CSINodeDriver
|
||||
}
|
||||
|
||||
var map_CSINodeList = map[string]string{
|
||||
"": "CSINodeList is a collection of CSINode objects.",
|
||||
"metadata": "Standard list metadata More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata",
|
||||
"items": "items is the list of CSINode",
|
||||
}
|
||||
|
||||
func (CSINodeList) SwaggerDoc() map[string]string {
|
||||
return map_CSINodeList
|
||||
}
|
||||
|
||||
var map_CSINodeSpec = map[string]string{
|
||||
"": "CSINodeSpec holds information about the specification of all CSI drivers installed on a node",
|
||||
"drivers": "drivers is a list of information of all CSI Drivers existing on a node. If all drivers in the list are uninstalled, this can become empty.",
|
||||
}
|
||||
|
||||
func (CSINodeSpec) SwaggerDoc() map[string]string {
|
||||
return map_CSINodeSpec
|
||||
}
|
||||
|
||||
var map_StorageClass = map[string]string{
|
||||
"": "StorageClass describes the parameters for a class of storage for which PersistentVolumes can be dynamically provisioned.\n\nStorageClasses are non-namespaced; the name of the storage class according to etcd is in ObjectMeta.Name.",
|
||||
"metadata": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata",
|
||||
|
|
|
@ -25,6 +25,196 @@ import (
|
|||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSIDriver) DeepCopyInto(out *CSIDriver) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriver.
|
||||
func (in *CSIDriver) DeepCopy() *CSIDriver {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSIDriver)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CSIDriver) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSIDriverList) DeepCopyInto(out *CSIDriverList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]CSIDriver, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriverList.
|
||||
func (in *CSIDriverList) DeepCopy() *CSIDriverList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSIDriverList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CSIDriverList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSIDriverSpec) DeepCopyInto(out *CSIDriverSpec) {
|
||||
*out = *in
|
||||
if in.AttachRequired != nil {
|
||||
in, out := &in.AttachRequired, &out.AttachRequired
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.PodInfoOnMount != nil {
|
||||
in, out := &in.PodInfoOnMount, &out.PodInfoOnMount
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriverSpec.
|
||||
func (in *CSIDriverSpec) DeepCopy() *CSIDriverSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSIDriverSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSINode) DeepCopyInto(out *CSINode) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINode.
|
||||
func (in *CSINode) DeepCopy() *CSINode {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSINode)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CSINode) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSINodeDriver) DeepCopyInto(out *CSINodeDriver) {
|
||||
*out = *in
|
||||
if in.TopologyKeys != nil {
|
||||
in, out := &in.TopologyKeys, &out.TopologyKeys
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeDriver.
|
||||
func (in *CSINodeDriver) DeepCopy() *CSINodeDriver {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSINodeDriver)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSINodeList) DeepCopyInto(out *CSINodeList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]CSINode, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeList.
|
||||
func (in *CSINodeList) DeepCopy() *CSINodeList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSINodeList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CSINodeList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CSINodeSpec) DeepCopyInto(out *CSINodeSpec) {
|
||||
*out = *in
|
||||
if in.Drivers != nil {
|
||||
in, out := &in.Drivers, &out.Drivers
|
||||
*out = make([]CSINodeDriver, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeSpec.
|
||||
func (in *CSINodeSpec) DeepCopy() *CSINodeSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CSINodeSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *StorageClass) DeepCopyInto(out *StorageClass) {
|
||||
*out = *in
|
||||
|
|
|
@ -280,6 +280,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
|
|||
return &genericInformer{resource: resource.GroupResource(), informer: f.Storage().V1alpha1().VolumeAttachments().Informer()}, nil
|
||||
|
||||
// Group=storage.k8s.io, Version=v1beta1
|
||||
case storagev1beta1.SchemeGroupVersion.WithResource("csidrivers"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Storage().V1beta1().CSIDrivers().Informer()}, nil
|
||||
case storagev1beta1.SchemeGroupVersion.WithResource("csinodes"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Storage().V1beta1().CSINodes().Informer()}, nil
|
||||
case storagev1beta1.SchemeGroupVersion.WithResource("storageclasses"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Storage().V1beta1().StorageClasses().Informer()}, nil
|
||||
case storagev1beta1.SchemeGroupVersion.WithResource("volumeattachments"):
|
||||
|
|
|
@ -8,6 +8,8 @@ load(
|
|||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"csidriver.go",
|
||||
"csinode.go",
|
||||
"interface.go",
|
||||
"storageclass.go",
|
||||
"volumeattachment.go",
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
storagev1beta1 "k8s.io/api/storage/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
|
||||
kubernetes "k8s.io/client-go/kubernetes"
|
||||
v1beta1 "k8s.io/client-go/listers/storage/v1beta1"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// CSIDriverInformer provides access to a shared informer and lister for
|
||||
// CSIDrivers.
|
||||
type CSIDriverInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1beta1.CSIDriverLister
|
||||
}
|
||||
|
||||
type cSIDriverInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// NewCSIDriverInformer constructs a new informer for CSIDriver type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewCSIDriverInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredCSIDriverInformer(client, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredCSIDriverInformer constructs a new informer for CSIDriver type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredCSIDriverInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.StorageV1beta1().CSIDrivers().List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.StorageV1beta1().CSIDrivers().Watch(options)
|
||||
},
|
||||
},
|
||||
&storagev1beta1.CSIDriver{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *cSIDriverInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredCSIDriverInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *cSIDriverInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&storagev1beta1.CSIDriver{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *cSIDriverInformer) Lister() v1beta1.CSIDriverLister {
|
||||
return v1beta1.NewCSIDriverLister(f.Informer().GetIndexer())
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
time "time"
|
||||
|
||||
storagev1beta1 "k8s.io/api/storage/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
internalinterfaces "k8s.io/client-go/informers/internalinterfaces"
|
||||
kubernetes "k8s.io/client-go/kubernetes"
|
||||
v1beta1 "k8s.io/client-go/listers/storage/v1beta1"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// CSINodeInformer provides access to a shared informer and lister for
|
||||
// CSINodes.
|
||||
type CSINodeInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() v1beta1.CSINodeLister
|
||||
}
|
||||
|
||||
type cSINodeInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
}
|
||||
|
||||
// NewCSINodeInformer constructs a new informer for CSINode type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewCSINodeInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredCSINodeInformer(client, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredCSINodeInformer constructs a new informer for CSINode type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredCSINodeInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.StorageV1beta1().CSINodes().List(options)
|
||||
},
|
||||
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.StorageV1beta1().CSINodes().Watch(options)
|
||||
},
|
||||
},
|
||||
&storagev1beta1.CSINode{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *cSINodeInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredCSINodeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *cSINodeInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&storagev1beta1.CSINode{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *cSINodeInformer) Lister() v1beta1.CSINodeLister {
|
||||
return v1beta1.NewCSINodeLister(f.Informer().GetIndexer())
|
||||
}
|
|
@ -24,6 +24,10 @@ import (
|
|||
|
||||
// Interface provides access to all the informers in this group version.
|
||||
type Interface interface {
|
||||
// CSIDrivers returns a CSIDriverInformer.
|
||||
CSIDrivers() CSIDriverInformer
|
||||
// CSINodes returns a CSINodeInformer.
|
||||
CSINodes() CSINodeInformer
|
||||
// StorageClasses returns a StorageClassInformer.
|
||||
StorageClasses() StorageClassInformer
|
||||
// VolumeAttachments returns a VolumeAttachmentInformer.
|
||||
|
@ -41,6 +45,16 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
|
|||
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
|
||||
}
|
||||
|
||||
// CSIDrivers returns a CSIDriverInformer.
|
||||
func (v *version) CSIDrivers() CSIDriverInformer {
|
||||
return &cSIDriverInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// CSINodes returns a CSINodeInformer.
|
||||
func (v *version) CSINodes() CSINodeInformer {
|
||||
return &cSINodeInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// StorageClasses returns a StorageClassInformer.
|
||||
func (v *version) StorageClasses() StorageClassInformer {
|
||||
return &storageClassInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
|
||||
|
|
|
@ -8,6 +8,8 @@ load(
|
|||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"csidriver.go",
|
||||
"csinode.go",
|
||||
"doc.go",
|
||||
"generated_expansion.go",
|
||||
"storage_client.go",
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
v1beta1 "k8s.io/api/storage/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
scheme "k8s.io/client-go/kubernetes/scheme"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// CSIDriversGetter has a method to return a CSIDriverInterface.
|
||||
// A group's client should implement this interface.
|
||||
type CSIDriversGetter interface {
|
||||
CSIDrivers() CSIDriverInterface
|
||||
}
|
||||
|
||||
// CSIDriverInterface has methods to work with CSIDriver resources.
|
||||
type CSIDriverInterface interface {
|
||||
Create(*v1beta1.CSIDriver) (*v1beta1.CSIDriver, error)
|
||||
Update(*v1beta1.CSIDriver) (*v1beta1.CSIDriver, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1beta1.CSIDriver, error)
|
||||
List(opts v1.ListOptions) (*v1beta1.CSIDriverList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CSIDriver, err error)
|
||||
CSIDriverExpansion
|
||||
}
|
||||
|
||||
// cSIDrivers implements CSIDriverInterface
|
||||
type cSIDrivers struct {
|
||||
client rest.Interface
|
||||
}
|
||||
|
||||
// newCSIDrivers returns a CSIDrivers
|
||||
func newCSIDrivers(c *StorageV1beta1Client) *cSIDrivers {
|
||||
return &cSIDrivers{
|
||||
client: c.RESTClient(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the cSIDriver, and returns the corresponding cSIDriver object, and an error if there is any.
|
||||
func (c *cSIDrivers) Get(name string, options v1.GetOptions) (result *v1beta1.CSIDriver, err error) {
|
||||
result = &v1beta1.CSIDriver{}
|
||||
err = c.client.Get().
|
||||
Resource("csidrivers").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of CSIDrivers that match those selectors.
|
||||
func (c *cSIDrivers) List(opts v1.ListOptions) (result *v1beta1.CSIDriverList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1beta1.CSIDriverList{}
|
||||
err = c.client.Get().
|
||||
Resource("csidrivers").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested cSIDrivers.
|
||||
func (c *cSIDrivers) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Resource("csidrivers").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a cSIDriver and creates it. Returns the server's representation of the cSIDriver, and an error, if there is any.
|
||||
func (c *cSIDrivers) Create(cSIDriver *v1beta1.CSIDriver) (result *v1beta1.CSIDriver, err error) {
|
||||
result = &v1beta1.CSIDriver{}
|
||||
err = c.client.Post().
|
||||
Resource("csidrivers").
|
||||
Body(cSIDriver).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a cSIDriver and updates it. Returns the server's representation of the cSIDriver, and an error, if there is any.
|
||||
func (c *cSIDrivers) Update(cSIDriver *v1beta1.CSIDriver) (result *v1beta1.CSIDriver, err error) {
|
||||
result = &v1beta1.CSIDriver{}
|
||||
err = c.client.Put().
|
||||
Resource("csidrivers").
|
||||
Name(cSIDriver.Name).
|
||||
Body(cSIDriver).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the cSIDriver and deletes it. Returns an error if one occurs.
|
||||
func (c *cSIDrivers) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Resource("csidrivers").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *cSIDrivers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Resource("csidrivers").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched cSIDriver.
|
||||
func (c *cSIDrivers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CSIDriver, err error) {
|
||||
result = &v1beta1.CSIDriver{}
|
||||
err = c.client.Patch(pt).
|
||||
Resource("csidrivers").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
v1beta1 "k8s.io/api/storage/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
scheme "k8s.io/client-go/kubernetes/scheme"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// CSINodesGetter has a method to return a CSINodeInterface.
|
||||
// A group's client should implement this interface.
|
||||
type CSINodesGetter interface {
|
||||
CSINodes() CSINodeInterface
|
||||
}
|
||||
|
||||
// CSINodeInterface has methods to work with CSINode resources.
|
||||
type CSINodeInterface interface {
|
||||
Create(*v1beta1.CSINode) (*v1beta1.CSINode, error)
|
||||
Update(*v1beta1.CSINode) (*v1beta1.CSINode, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1beta1.CSINode, error)
|
||||
List(opts v1.ListOptions) (*v1beta1.CSINodeList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CSINode, err error)
|
||||
CSINodeExpansion
|
||||
}
|
||||
|
||||
// cSINodes implements CSINodeInterface
|
||||
type cSINodes struct {
|
||||
client rest.Interface
|
||||
}
|
||||
|
||||
// newCSINodes returns a CSINodes
|
||||
func newCSINodes(c *StorageV1beta1Client) *cSINodes {
|
||||
return &cSINodes{
|
||||
client: c.RESTClient(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the cSINode, and returns the corresponding cSINode object, and an error if there is any.
|
||||
func (c *cSINodes) Get(name string, options v1.GetOptions) (result *v1beta1.CSINode, err error) {
|
||||
result = &v1beta1.CSINode{}
|
||||
err = c.client.Get().
|
||||
Resource("csinodes").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of CSINodes that match those selectors.
|
||||
func (c *cSINodes) List(opts v1.ListOptions) (result *v1beta1.CSINodeList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1beta1.CSINodeList{}
|
||||
err = c.client.Get().
|
||||
Resource("csinodes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested cSINodes.
|
||||
func (c *cSINodes) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Resource("csinodes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a cSINode and creates it. Returns the server's representation of the cSINode, and an error, if there is any.
|
||||
func (c *cSINodes) Create(cSINode *v1beta1.CSINode) (result *v1beta1.CSINode, err error) {
|
||||
result = &v1beta1.CSINode{}
|
||||
err = c.client.Post().
|
||||
Resource("csinodes").
|
||||
Body(cSINode).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a cSINode and updates it. Returns the server's representation of the cSINode, and an error, if there is any.
|
||||
func (c *cSINodes) Update(cSINode *v1beta1.CSINode) (result *v1beta1.CSINode, err error) {
|
||||
result = &v1beta1.CSINode{}
|
||||
err = c.client.Put().
|
||||
Resource("csinodes").
|
||||
Name(cSINode.Name).
|
||||
Body(cSINode).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the cSINode and deletes it. Returns an error if one occurs.
|
||||
func (c *cSINodes) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Resource("csinodes").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *cSINodes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Resource("csinodes").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched cSINode.
|
||||
func (c *cSINodes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CSINode, err error) {
|
||||
result = &v1beta1.CSINode{}
|
||||
err = c.client.Patch(pt).
|
||||
Resource("csinodes").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
|
@ -9,6 +9,8 @@ go_library(
|
|||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"fake_csidriver.go",
|
||||
"fake_csinode.go",
|
||||
"fake_storage_client.go",
|
||||
"fake_storageclass.go",
|
||||
"fake_volumeattachment.go",
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1beta1 "k8s.io/api/storage/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeCSIDrivers implements CSIDriverInterface
|
||||
type FakeCSIDrivers struct {
|
||||
Fake *FakeStorageV1beta1
|
||||
}
|
||||
|
||||
var csidriversResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1beta1", Resource: "csidrivers"}
|
||||
|
||||
var csidriversKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSIDriver"}
|
||||
|
||||
// Get takes name of the cSIDriver, and returns the corresponding cSIDriver object, and an error if there is any.
|
||||
func (c *FakeCSIDrivers) Get(name string, options v1.GetOptions) (result *v1beta1.CSIDriver, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootGetAction(csidriversResource, name), &v1beta1.CSIDriver{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.CSIDriver), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of CSIDrivers that match those selectors.
|
||||
func (c *FakeCSIDrivers) List(opts v1.ListOptions) (result *v1beta1.CSIDriverList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootListAction(csidriversResource, csidriversKind, opts), &v1beta1.CSIDriverList{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1beta1.CSIDriverList{ListMeta: obj.(*v1beta1.CSIDriverList).ListMeta}
|
||||
for _, item := range obj.(*v1beta1.CSIDriverList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested cSIDrivers.
|
||||
func (c *FakeCSIDrivers) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewRootWatchAction(csidriversResource, opts))
|
||||
}
|
||||
|
||||
// Create takes the representation of a cSIDriver and creates it. Returns the server's representation of the cSIDriver, and an error, if there is any.
|
||||
func (c *FakeCSIDrivers) Create(cSIDriver *v1beta1.CSIDriver) (result *v1beta1.CSIDriver, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootCreateAction(csidriversResource, cSIDriver), &v1beta1.CSIDriver{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.CSIDriver), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a cSIDriver and updates it. Returns the server's representation of the cSIDriver, and an error, if there is any.
|
||||
func (c *FakeCSIDrivers) Update(cSIDriver *v1beta1.CSIDriver) (result *v1beta1.CSIDriver, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootUpdateAction(csidriversResource, cSIDriver), &v1beta1.CSIDriver{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.CSIDriver), err
|
||||
}
|
||||
|
||||
// Delete takes name of the cSIDriver and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeCSIDrivers) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewRootDeleteAction(csidriversResource, name), &v1beta1.CSIDriver{})
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeCSIDrivers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewRootDeleteCollectionAction(csidriversResource, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1beta1.CSIDriverList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched cSIDriver.
|
||||
func (c *FakeCSIDrivers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CSIDriver, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootPatchSubresourceAction(csidriversResource, name, pt, data, subresources...), &v1beta1.CSIDriver{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.CSIDriver), err
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1beta1 "k8s.io/api/storage/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeCSINodes implements CSINodeInterface
|
||||
type FakeCSINodes struct {
|
||||
Fake *FakeStorageV1beta1
|
||||
}
|
||||
|
||||
var csinodesResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1beta1", Resource: "csinodes"}
|
||||
|
||||
var csinodesKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSINode"}
|
||||
|
||||
// Get takes name of the cSINode, and returns the corresponding cSINode object, and an error if there is any.
|
||||
func (c *FakeCSINodes) Get(name string, options v1.GetOptions) (result *v1beta1.CSINode, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootGetAction(csinodesResource, name), &v1beta1.CSINode{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.CSINode), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of CSINodes that match those selectors.
|
||||
func (c *FakeCSINodes) List(opts v1.ListOptions) (result *v1beta1.CSINodeList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootListAction(csinodesResource, csinodesKind, opts), &v1beta1.CSINodeList{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1beta1.CSINodeList{ListMeta: obj.(*v1beta1.CSINodeList).ListMeta}
|
||||
for _, item := range obj.(*v1beta1.CSINodeList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested cSINodes.
|
||||
func (c *FakeCSINodes) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewRootWatchAction(csinodesResource, opts))
|
||||
}
|
||||
|
||||
// Create takes the representation of a cSINode and creates it. Returns the server's representation of the cSINode, and an error, if there is any.
|
||||
func (c *FakeCSINodes) Create(cSINode *v1beta1.CSINode) (result *v1beta1.CSINode, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootCreateAction(csinodesResource, cSINode), &v1beta1.CSINode{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.CSINode), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a cSINode and updates it. Returns the server's representation of the cSINode, and an error, if there is any.
|
||||
func (c *FakeCSINodes) Update(cSINode *v1beta1.CSINode) (result *v1beta1.CSINode, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootUpdateAction(csinodesResource, cSINode), &v1beta1.CSINode{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.CSINode), err
|
||||
}
|
||||
|
||||
// Delete takes name of the cSINode and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeCSINodes) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewRootDeleteAction(csinodesResource, name), &v1beta1.CSINode{})
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeCSINodes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewRootDeleteCollectionAction(csinodesResource, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1beta1.CSINodeList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched cSINode.
|
||||
func (c *FakeCSINodes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CSINode, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewRootPatchSubresourceAction(csinodesResource, name, pt, data, subresources...), &v1beta1.CSINode{})
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.CSINode), err
|
||||
}
|
|
@ -28,6 +28,14 @@ type FakeStorageV1beta1 struct {
|
|||
*testing.Fake
|
||||
}
|
||||
|
||||
func (c *FakeStorageV1beta1) CSIDrivers() v1beta1.CSIDriverInterface {
|
||||
return &FakeCSIDrivers{c}
|
||||
}
|
||||
|
||||
func (c *FakeStorageV1beta1) CSINodes() v1beta1.CSINodeInterface {
|
||||
return &FakeCSINodes{c}
|
||||
}
|
||||
|
||||
func (c *FakeStorageV1beta1) StorageClasses() v1beta1.StorageClassInterface {
|
||||
return &FakeStorageClasses{c}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue