Merge pull request #74283 from xing-yang/csi_crd_controller

CSINodeInfo and CSIDriver Controller Changes
pull/564/head
Kubernetes Prow Robot 2019-03-05 04:44:42 -08:00 committed by GitHub
commit 6c31101257
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
118 changed files with 8166 additions and 1047 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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",

View File

@ -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(),

View File

@ -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",

View File

@ -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 {

View File

@ -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 ###

View File

@ -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"}: {},

View File

@ -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
}

View File

@ -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",

View File

@ -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
}
},
}
}

View File

@ -48,6 +48,10 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&StorageClassList{},
&VolumeAttachment{},
&VolumeAttachmentList{},
&CSINode{},
&CSINodeList{},
&CSIDriver{},
&CSIDriverList{},
)
return nil
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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)
}

View File

@ -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
}

View File

@ -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: &notPodInfoOnMount,
},
},
{
// 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: &notPodInfoOnMount,
},
},
{
ObjectMeta: metav1.ObjectMeta{Name: driverName},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachRequired,
PodInfoOnMount: &podInfoOnMount,
},
},
{
ObjectMeta: metav1.ObjectMeta{Name: driverName},
Spec: storage.CSIDriverSpec{
AttachRequired: &attachNotRequired,
PodInfoOnMount: &notPodInfoOnMount,
},
},
}
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: &notPodInfoOnMount,
},
},
{
// 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)
}
}
}

View File

@ -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

View File

@ -8,6 +8,8 @@ load(
go_library(
name = "go_default_library",
srcs = [
"csidriver.go",
"csinode.go",
"doc.go",
"generated_expansion.go",
"storage_client.go",

View File

@ -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
}

View File

@ -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
}

View File

@ -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",

View File

@ -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
}

View File

@ -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
}

View File

@ -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}
}

View File

@ -18,6 +18,10 @@ limitations under the License.
package internalversion
type CSIDriverExpansion interface{}
type CSINodeExpansion interface{}
type StorageClassExpansion interface{}
type VolumeAttachmentExpansion interface{}

View File

@ -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)
}

View File

@ -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",
],
)

View File

@ -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

View File

@ -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(),

View File

@ -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",
],
)

View File

@ -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

View File

@ -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",

View File

@ -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

View File

@ -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},

View File

@ -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",
],
)

View File

@ -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,
}
}

View File

@ -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",

View File

@ -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

View File

@ -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
}

View File

@ -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",

View File

@ -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",
],
)

View File

@ -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

View File

@ -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",
],
)

View File

@ -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},
}
}

View File

@ -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: &notPodInfoOnMount,
},
},
)
}
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 = &notPodInfoOnMount
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"},
},
)
}

View File

@ -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
}

View File

@ -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: &notAttachRequired,
PodInfoOnMount: &notPodInfoOnMount,
},
},
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")
}
})
}
}

View File

@ -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",
],
)

View File

@ -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

View File

@ -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",
],
)

View File

@ -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},
}
}

View File

@ -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"},
},
)
}

View File

@ -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
}

View File

@ -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")
}
})
}
}

View File

@ -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",
],
)

View File

@ -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
}

View File

@ -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",
],
)

View File

@ -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",
],

View File

@ -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",
)

View File

@ -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

View File

@ -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
}

View File

@ -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", &currentPodInfoMountVersion, nil),
fakeClient := fakeclient.NewSimpleClientset(
getCSIDriver("no-info", &noPodMountInfo, nil),
getCSIDriver("info", &currentPodInfoMount, 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,
},
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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",
],
)

View File

@ -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

View File

@ -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

View File

@ -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",
],

View File

@ -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
}

View File

@ -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",
],
)

View File

@ -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"))
}
}

View File

@ -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: "",
},

View File

@ -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",

View File

@ -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

View File

@ -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,
},

View File

@ -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())
}
}

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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.
//

View File

@ -49,6 +49,12 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&VolumeAttachment{},
&VolumeAttachmentList{},
&CSIDriver{},
&CSIDriverList{},
&CSINode{},
&CSINodeList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)

View File

@ -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"`
}

View File

@ -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",

View File

@ -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

View File

@ -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"):

View File

@ -8,6 +8,8 @@ load(
go_library(
name = "go_default_library",
srcs = [
"csidriver.go",
"csinode.go",
"interface.go",
"storageclass.go",
"volumeattachment.go",

View File

@ -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())
}

View File

@ -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())
}

View File

@ -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}

View File

@ -8,6 +8,8 @@ load(
go_library(
name = "go_default_library",
srcs = [
"csidriver.go",
"csinode.go",
"doc.go",
"generated_expansion.go",
"storage_client.go",

View File

@ -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
}

View File

@ -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
}

View File

@ -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",

View File

@ -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
}

View File

@ -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
}

View File

@ -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