mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-07 11:13:48 +00:00
Merge pull request #70515 from davidz627/feature/csiNodeInfo
Add explicit "Installed" field to CSINodeInfo and change update semantics
This commit is contained in:
commit
e133ab274d
@ -13,11 +13,15 @@ spec:
|
|||||||
validation:
|
validation:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
properties:
|
properties:
|
||||||
csiDrivers:
|
spec:
|
||||||
description: List of CSI drivers running on the node and their properties.
|
description: Specification of CSINodeInfo
|
||||||
|
properties:
|
||||||
|
drivers:
|
||||||
|
description: List of CSI drivers running on the node and their specs.
|
||||||
|
type: array
|
||||||
items:
|
items:
|
||||||
properties:
|
properties:
|
||||||
driver:
|
name:
|
||||||
description: The CSI driver that this object refers to.
|
description: The CSI driver that this object refers to.
|
||||||
type: string
|
type: string
|
||||||
nodeID:
|
nodeID:
|
||||||
@ -28,5 +32,23 @@ spec:
|
|||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
status:
|
||||||
|
description: Status of CSINodeInfo
|
||||||
|
properties:
|
||||||
|
drivers:
|
||||||
|
description: List of CSI drivers running on the node and their statuses.
|
||||||
type: array
|
type: array
|
||||||
|
items:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: The CSI driver that this object refers to.
|
||||||
|
type: string
|
||||||
|
available:
|
||||||
|
description: Whether the CSI driver is installed.
|
||||||
|
type: boolean
|
||||||
|
volumePluginMechanism:
|
||||||
|
description: Indicates to external components the required mechanism
|
||||||
|
to use for any in-tree plugins replaced by this driver.
|
||||||
|
pattern: in-tree|csi
|
||||||
|
type: string
|
||||||
version: v1alpha1
|
version: v1alpha1
|
||||||
|
@ -146,7 +146,7 @@ func (h *RegistrationHandler) RegisterPlugin(pluginName string, endpoint string)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = nim.AddNodeInfo(pluginName, driverNodeID, maxVolumePerNode, accessibleTopology)
|
err = nim.InstallCSIDriver(pluginName, driverNodeID, maxVolumePerNode, accessibleTopology)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Error(log("registrationHandler.RegisterPlugin failed at AddNodeInfo: %v", err))
|
glog.Error(log("registrationHandler.RegisterPlugin failed at AddNodeInfo: %v", err))
|
||||||
if unregErr := unregisterDriver(pluginName); unregErr != nil {
|
if unregErr := unregisterDriver(pluginName); unregErr != nil {
|
||||||
@ -188,6 +188,9 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error {
|
|||||||
csiDrivers = csiDriversStore{driversMap: map[string]csiDriver{}}
|
csiDrivers = csiDriversStore{driversMap: map[string]csiDriver{}}
|
||||||
nim = nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host)
|
nim = nodeinfomanager.NewNodeInfoManager(host.GetNodeName(), host)
|
||||||
|
|
||||||
|
// TODO(#70514) Init CSINodeInfo object if the CRD exists and create Driver
|
||||||
|
// objects for migrated drivers.
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,8 +586,8 @@ func unregisterDriver(driverName string) error {
|
|||||||
delete(csiDrivers.driversMap, driverName)
|
delete(csiDrivers.driversMap, driverName)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err := nim.RemoveNodeInfo(driverName); err != nil {
|
if err := nim.UninstallCSIDriver(driverName); err != nil {
|
||||||
glog.Errorf("Error unregistering CSI driver: %v", err)
|
glog.Errorf("Error uninstalling CSI driver: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,6 @@ go_test(
|
|||||||
"//pkg/volume/testing:go_default_library",
|
"//pkg/volume/testing:go_default_library",
|
||||||
"//pkg/volume/util:go_default_library",
|
"//pkg/volume/util:go_default_library",
|
||||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
"//staging/src/k8s.io/api/core/v1: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/api/resource:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1: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",
|
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
|
@ -58,15 +58,17 @@ type nodeUpdateFunc func(*v1.Node) (newNode *v1.Node, updated bool, err error)
|
|||||||
|
|
||||||
// Interface implements an interface for managing labels of a node
|
// Interface implements an interface for managing labels of a node
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
|
CreateCSINodeInfo() (*csiv1alpha1.CSINodeInfo, error)
|
||||||
|
|
||||||
// Record in the cluster the given node information from the CSI driver with the given name.
|
// Record in the cluster the given node information from the CSI driver with the given name.
|
||||||
// Concurrent calls to AddNodeInfo() is allowed, but they should not be intertwined with calls
|
// Concurrent calls to InstallCSIDriver() is allowed, but they should not be intertwined with calls
|
||||||
// to other methods in this interface.
|
// to other methods in this interface.
|
||||||
AddNodeInfo(driverName string, driverNodeID string, maxVolumeLimit int64, topology *csipb.Topology) error
|
InstallCSIDriver(driverName string, driverNodeID string, maxVolumeLimit int64, topology *csipb.Topology) error
|
||||||
|
|
||||||
// Remove in the cluster node information from the CSI driver with the given name.
|
// Remove in the cluster node information from the CSI driver with the given name.
|
||||||
// Concurrent calls to RemoveNodeInfo() is allowed, but they should not be intertwined with calls
|
// Concurrent calls to UninstallCSIDriver() is allowed, but they should not be intertwined with calls
|
||||||
// to other methods in this interface.
|
// to other methods in this interface.
|
||||||
RemoveNodeInfo(driverName string) error
|
UninstallCSIDriver(driverName string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNodeInfoManager initializes nodeInfoManager
|
// NewNodeInfoManager initializes nodeInfoManager
|
||||||
@ -79,11 +81,11 @@ func NewNodeInfoManager(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddNodeInfo updates the node ID annotation in the Node object and CSIDrivers field in the
|
// 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.
|
// CSINodeInfo object. If the CSINodeInfo object doesn't yet exist, it will be created.
|
||||||
// If multiple calls to AddNodeInfo() are made in parallel, some calls might receive Node or
|
// 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.
|
// CSINodeInfo update conflicts, which causes the function to retry the corresponding update.
|
||||||
func (nim *nodeInfoManager) AddNodeInfo(driverName string, driverNodeID string, maxAttachLimit int64, topology *csipb.Topology) error {
|
func (nim *nodeInfoManager) InstallCSIDriver(driverName string, driverNodeID string, maxAttachLimit int64, topology *csipb.Topology) error {
|
||||||
if driverNodeID == "" {
|
if driverNodeID == "" {
|
||||||
return fmt.Errorf("error adding CSI driver node info: driverNodeID must not be empty")
|
return fmt.Errorf("error adding CSI driver node info: driverNodeID must not be empty")
|
||||||
}
|
}
|
||||||
@ -114,14 +116,14 @@ func (nim *nodeInfoManager) AddNodeInfo(driverName string, driverNodeID string,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveNodeInfo removes the node ID annotation from the Node object and CSIDrivers field from the
|
// 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.
|
// CSINodeInfo object. If the CSINOdeInfo object contains no CSIDrivers, it will be deleted.
|
||||||
// If multiple calls to RemoveNodeInfo() are made in parallel, some calls might receive Node or
|
// 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.
|
// CSINodeInfo update conflicts, which causes the function to retry the corresponding update.
|
||||||
func (nim *nodeInfoManager) RemoveNodeInfo(driverName string) error {
|
func (nim *nodeInfoManager) UninstallCSIDriver(driverName string) error {
|
||||||
err := nim.removeCSINodeInfo(driverName)
|
err := nim.uninstallDriverFromCSINodeInfo(driverName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error removing CSI driver node info from CSINodeInfo object %v", err)
|
return fmt.Errorf("error uninstalling CSI driver from CSINodeInfo object %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = nim.updateNode(
|
err = nim.updateNode(
|
||||||
@ -333,13 +335,13 @@ func (nim *nodeInfoManager) updateCSINodeInfo(
|
|||||||
retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||||
nodeInfo, err := csiKubeClient.CsiV1alpha1().CSINodeInfos().Get(string(nim.nodeName), metav1.GetOptions{})
|
nodeInfo, err := csiKubeClient.CsiV1alpha1().CSINodeInfos().Get(string(nim.nodeName), metav1.GetOptions{})
|
||||||
if nodeInfo == nil || errors.IsNotFound(err) {
|
if nodeInfo == nil || errors.IsNotFound(err) {
|
||||||
return nim.createNodeInfoObject(driverName, driverNodeID, topology)
|
nodeInfo, err = nim.CreateCSINodeInfo()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err // do not wrap error
|
return err // do not wrap error
|
||||||
}
|
}
|
||||||
|
|
||||||
return nim.updateNodeInfoObject(nodeInfo, driverName, driverNodeID, topology)
|
return nim.installDriverToCSINodeInfo(nodeInfo, driverName, driverNodeID, topology)
|
||||||
})
|
})
|
||||||
if retryErr != nil {
|
if retryErr != nil {
|
||||||
return fmt.Errorf("CSINodeInfo update failed: %v", retryErr)
|
return fmt.Errorf("CSINodeInfo update failed: %v", retryErr)
|
||||||
@ -347,31 +349,21 @@ func (nim *nodeInfoManager) updateCSINodeInfo(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nim *nodeInfoManager) createNodeInfoObject(
|
func (nim *nodeInfoManager) CreateCSINodeInfo() (*csiv1alpha1.CSINodeInfo, error) {
|
||||||
driverName string,
|
|
||||||
driverNodeID string,
|
|
||||||
topology *csipb.Topology) error {
|
|
||||||
|
|
||||||
kubeClient := nim.volumeHost.GetKubeClient()
|
kubeClient := nim.volumeHost.GetKubeClient()
|
||||||
if kubeClient == nil {
|
if kubeClient == nil {
|
||||||
return fmt.Errorf("error getting kube client")
|
return nil, fmt.Errorf("error getting kube client")
|
||||||
}
|
}
|
||||||
|
|
||||||
csiKubeClient := nim.volumeHost.GetCSIClient()
|
csiKubeClient := nim.volumeHost.GetCSIClient()
|
||||||
if csiKubeClient == nil {
|
if csiKubeClient == nil {
|
||||||
return fmt.Errorf("error getting CSI client")
|
return nil, fmt.Errorf("error getting CSI client")
|
||||||
}
|
|
||||||
|
|
||||||
topologyKeys := []string{} // must be an empty slice instead of nil to satisfy CRD OpenAPI Schema validation
|
|
||||||
if topology != nil {
|
|
||||||
for k := range topology.Segments {
|
|
||||||
topologyKeys = append(topologyKeys, k)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err := kubeClient.CoreV1().Nodes().Get(string(nim.nodeName), metav1.GetOptions{})
|
node, err := kubeClient.CoreV1().Nodes().Get(string(nim.nodeName), metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err // do not wrap error
|
return nil, err // do not wrap error
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeInfo := &csiv1alpha1.CSINodeInfo{
|
nodeInfo := &csiv1alpha1.CSINodeInfo{
|
||||||
@ -386,20 +378,18 @@ func (nim *nodeInfoManager) createNodeInfoObject(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CSIDrivers: []csiv1alpha1.CSIDriverInfo{
|
Spec: csiv1alpha1.CSINodeInfoSpec{
|
||||||
{
|
Drivers: []csiv1alpha1.CSIDriverInfoSpec{},
|
||||||
Driver: driverName,
|
|
||||||
NodeID: driverNodeID,
|
|
||||||
TopologyKeys: topologyKeys,
|
|
||||||
},
|
},
|
||||||
|
Status: csiv1alpha1.CSINodeInfoStatus{
|
||||||
|
Drivers: []csiv1alpha1.CSIDriverInfoStatus{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = csiKubeClient.CsiV1alpha1().CSINodeInfos().Create(nodeInfo)
|
return csiKubeClient.CsiV1alpha1().CSINodeInfos().Create(nodeInfo)
|
||||||
return err // do not wrap error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nim *nodeInfoManager) updateNodeInfoObject(
|
func (nim *nodeInfoManager) installDriverToCSINodeInfo(
|
||||||
nodeInfo *csiv1alpha1.CSINodeInfo,
|
nodeInfo *csiv1alpha1.CSINodeInfo,
|
||||||
driverName string,
|
driverName string,
|
||||||
driverNodeID string,
|
driverNodeID string,
|
||||||
@ -417,36 +407,62 @@ func (nim *nodeInfoManager) updateNodeInfoObject(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone driver list, omitting the driver that matches the given driverName,
|
specModified := true
|
||||||
// unless the driver is identical to information provided, in which case no update is necessary.
|
statusModified := true
|
||||||
var newDriverInfos []csiv1alpha1.CSIDriverInfo
|
// Clone driver list, omitting the driver that matches the given driverName
|
||||||
for _, driverInfo := range nodeInfo.CSIDrivers {
|
newDriverSpecs := []csiv1alpha1.CSIDriverInfoSpec{}
|
||||||
if driverInfo.Driver == driverName {
|
for _, driverInfoSpec := range nodeInfo.Spec.Drivers {
|
||||||
prevTopologyKeys := sets.NewString(driverInfo.TopologyKeys...)
|
if driverInfoSpec.Name == driverName {
|
||||||
if driverInfo.NodeID == driverNodeID && prevTopologyKeys.Equal(topologyKeys) {
|
if driverInfoSpec.NodeID == driverNodeID &&
|
||||||
// No update needed
|
sets.NewString(driverInfoSpec.TopologyKeys...).Equal(topologyKeys) {
|
||||||
return nil
|
specModified = false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Omit driverInfo matching given driverName
|
// Omit driverInfoSpec matching given driverName
|
||||||
newDriverInfos = append(newDriverInfos, driverInfo)
|
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
|
// Append new driver
|
||||||
driverInfo := csiv1alpha1.CSIDriverInfo{
|
driverSpec := csiv1alpha1.CSIDriverInfoSpec{
|
||||||
Driver: driverName,
|
Name: driverName,
|
||||||
NodeID: driverNodeID,
|
NodeID: driverNodeID,
|
||||||
TopologyKeys: topologyKeys.List(),
|
TopologyKeys: topologyKeys.List(),
|
||||||
}
|
}
|
||||||
newDriverInfos = append(newDriverInfos, driverInfo)
|
driverStatus := csiv1alpha1.CSIDriverInfoStatus{
|
||||||
nodeInfo.CSIDrivers = newDriverInfos
|
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 := csiKubeClient.CsiV1alpha1().CSINodeInfos().Update(nodeInfo)
|
_, err := csiKubeClient.CsiV1alpha1().CSINodeInfos().Update(nodeInfo)
|
||||||
return err // do not wrap error
|
return err // do not wrap error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nim *nodeInfoManager) removeCSINodeInfo(csiDriverName string) error {
|
func (nim *nodeInfoManager) uninstallDriverFromCSINodeInfo(csiDriverName string) error {
|
||||||
retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||||
|
|
||||||
csiKubeClient := nim.volumeHost.GetCSIClient()
|
csiKubeClient := nim.volumeHost.GetCSIClient()
|
||||||
@ -456,32 +472,28 @@ func (nim *nodeInfoManager) removeCSINodeInfo(csiDriverName string) error {
|
|||||||
|
|
||||||
nodeInfoClient := csiKubeClient.CsiV1alpha1().CSINodeInfos()
|
nodeInfoClient := csiKubeClient.CsiV1alpha1().CSINodeInfos()
|
||||||
nodeInfo, err := nodeInfoClient.Get(string(nim.nodeName), metav1.GetOptions{})
|
nodeInfo, err := nodeInfoClient.Get(string(nim.nodeName), metav1.GetOptions{})
|
||||||
if nodeInfo == nil || errors.IsNotFound(err) {
|
|
||||||
// do nothing
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err // do not wrap error
|
return err // do not wrap error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove matching driver from driver list
|
hasModified := false
|
||||||
var newDriverInfos []csiv1alpha1.CSIDriverInfo
|
newDriverStatuses := []csiv1alpha1.CSIDriverInfoStatus{}
|
||||||
for _, driverInfo := range nodeInfo.CSIDrivers {
|
for _, driverStatus := range nodeInfo.Status.Drivers {
|
||||||
if driverInfo.Driver != csiDriverName {
|
if driverStatus.Name == csiDriverName {
|
||||||
newDriverInfos = append(newDriverInfos, driverInfo)
|
// Uninstall the driver if we find it
|
||||||
|
hasModified = driverStatus.Available
|
||||||
|
driverStatus.Available = false
|
||||||
}
|
}
|
||||||
|
newDriverStatuses = append(newDriverStatuses, driverStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(newDriverInfos) == len(nodeInfo.CSIDrivers) {
|
nodeInfo.Status.Drivers = newDriverStatuses
|
||||||
|
|
||||||
|
if !hasModified {
|
||||||
// No changes, don't update
|
// No changes, don't update
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(newDriverInfos) == 0 {
|
|
||||||
// No drivers left, delete CSINodeInfo object
|
|
||||||
return nodeInfoClient.Delete(string(nim.nodeName), &metav1.DeleteOptions{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO (verult) make sure CSINodeInfo has validation logic to prevent duplicate driver names
|
// TODO (verult) make sure CSINodeInfo has validation logic to prevent duplicate driver names
|
||||||
_, updateErr := nodeInfoClient.Update(nodeInfo)
|
_, updateErr := nodeInfoClient.Update(nodeInfo)
|
||||||
return updateErr // do not wrap error
|
return updateErr // do not wrap error
|
||||||
|
@ -24,7 +24,6 @@ import (
|
|||||||
"github.com/container-storage-interface/spec/lib/go/csi/v0"
|
"github.com/container-storage-interface/spec/lib/go/csi/v0"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
@ -55,7 +54,6 @@ type testcase struct {
|
|||||||
expectedNodeIDMap map[string]string
|
expectedNodeIDMap map[string]string
|
||||||
expectedTopologyMap map[string]sets.String
|
expectedTopologyMap map[string]sets.String
|
||||||
expectedLabels map[string]string
|
expectedLabels map[string]string
|
||||||
expectNoNodeInfo bool
|
|
||||||
expectedVolumeLimit int64
|
expectedVolumeLimit int64
|
||||||
expectFail bool
|
expectFail bool
|
||||||
}
|
}
|
||||||
@ -64,9 +62,9 @@ type nodeIDMap map[string]string
|
|||||||
type topologyKeyMap map[string][]string
|
type topologyKeyMap map[string][]string
|
||||||
type labelMap map[string]string
|
type labelMap map[string]string
|
||||||
|
|
||||||
// TestAddNodeInfo tests AddNodeInfo with various existing Node and/or CSINodeInfo objects.
|
// TestInstallCSIDriver tests InstallCSIDriver with various existing Node and/or CSINodeInfo objects.
|
||||||
// The node IDs in all test cases below are the same between the Node annotation and CSINodeInfo.
|
// The node IDs in all test cases below are the same between the Node annotation and CSINodeInfo.
|
||||||
func TestAddNodeInfo(t *testing.T) {
|
func TestInstallCSIDriver(t *testing.T) {
|
||||||
testcases := []testcase{
|
testcases := []testcase{
|
||||||
{
|
{
|
||||||
name: "empty node",
|
name: "empty node",
|
||||||
@ -375,9 +373,9 @@ func TestAddNodeInfo(t *testing.T) {
|
|||||||
test(t, true /* addNodeInfo */, true /* csiNodeInfoEnabled */, testcases)
|
test(t, true /* addNodeInfo */, true /* csiNodeInfoEnabled */, testcases)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestAddNodeInfo_CSINodeInfoDisabled tests AddNodeInfo with various existing Node annotations
|
// TestInstallCSIDriver_CSINodeInfoDisabled tests InstallCSIDriver with various existing Node annotations
|
||||||
// and CSINodeInfo feature gate disabled.
|
// and CSINodeInfo feature gate disabled.
|
||||||
func TestAddNodeInfo_CSINodeInfoDisabled(t *testing.T) {
|
func TestInstallCSIDriver_CSINodeInfoDisabled(t *testing.T) {
|
||||||
testcases := []testcase{
|
testcases := []testcase{
|
||||||
{
|
{
|
||||||
name: "empty node",
|
name: "empty node",
|
||||||
@ -420,16 +418,15 @@ func TestAddNodeInfo_CSINodeInfoDisabled(t *testing.T) {
|
|||||||
test(t, true /* addNodeInfo */, false /* csiNodeInfoEnabled */, testcases)
|
test(t, true /* addNodeInfo */, false /* csiNodeInfoEnabled */, testcases)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRemoveNodeInfo tests RemoveNodeInfo with various existing Node and/or CSINodeInfo objects.
|
// TestUninstallCSIDriver tests UninstallCSIDriver with various existing Node and/or CSINodeInfo objects.
|
||||||
func TestRemoveNodeInfo(t *testing.T) {
|
func TestUninstallCSIDriver(t *testing.T) {
|
||||||
testcases := []testcase{
|
testcases := []testcase{
|
||||||
{
|
{
|
||||||
name: "empty node and no CSINodeInfo",
|
name: "empty node and empty CSINodeInfo",
|
||||||
driverName: "com.example.csi/driver1",
|
driverName: "com.example.csi/driver1",
|
||||||
existingNode: generateNode(nil /* nodeIDs */, nil /* labels */, nil /*capacity*/),
|
existingNode: generateNode(nil /* nodeIDs */, nil /* labels */, nil /*capacity*/),
|
||||||
expectedNodeIDMap: nil,
|
expectedNodeIDMap: nil,
|
||||||
expectedLabels: nil,
|
expectedLabels: nil,
|
||||||
expectNoNodeInfo: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pre-existing node info from the same driver",
|
name: "pre-existing node info from the same driver",
|
||||||
@ -451,7 +448,6 @@ func TestRemoveNodeInfo(t *testing.T) {
|
|||||||
),
|
),
|
||||||
expectedNodeIDMap: nil,
|
expectedNodeIDMap: nil,
|
||||||
expectedLabels: map[string]string{"com.example.csi/zone": "zoneA"},
|
expectedLabels: map[string]string{"com.example.csi/zone": "zoneA"},
|
||||||
expectNoNodeInfo: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pre-existing node info from different driver",
|
name: "pre-existing node info from different driver",
|
||||||
@ -480,7 +476,7 @@ func TestRemoveNodeInfo(t *testing.T) {
|
|||||||
expectedLabels: map[string]string{"net.example.storage/zone": "zoneA"},
|
expectedLabels: map[string]string{"net.example.storage/zone": "zoneA"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pre-existing info about the same driver in node, but no CSINodeInfo",
|
name: "pre-existing info about the same driver in node, but empty CSINodeInfo",
|
||||||
driverName: "com.example.csi/driver1",
|
driverName: "com.example.csi/driver1",
|
||||||
existingNode: generateNode(
|
existingNode: generateNode(
|
||||||
nodeIDMap{
|
nodeIDMap{
|
||||||
@ -489,10 +485,9 @@ func TestRemoveNodeInfo(t *testing.T) {
|
|||||||
nil /* labels */, nil /*capacity*/),
|
nil /* labels */, nil /*capacity*/),
|
||||||
expectedNodeIDMap: nil,
|
expectedNodeIDMap: nil,
|
||||||
expectedLabels: nil,
|
expectedLabels: nil,
|
||||||
expectNoNodeInfo: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pre-existing info about a different driver in node, but no CSINodeInfo",
|
name: "pre-existing info about a different driver in node, but empty CSINodeInfo",
|
||||||
existingNode: generateNode(
|
existingNode: generateNode(
|
||||||
nodeIDMap{
|
nodeIDMap{
|
||||||
"net.example.storage/other-driver": "net.example.storage/csi-node1",
|
"net.example.storage/other-driver": "net.example.storage/csi-node1",
|
||||||
@ -502,7 +497,6 @@ func TestRemoveNodeInfo(t *testing.T) {
|
|||||||
"net.example.storage/other-driver": "net.example.storage/csi-node1",
|
"net.example.storage/other-driver": "net.example.storage/csi-node1",
|
||||||
},
|
},
|
||||||
expectedLabels: nil,
|
expectedLabels: nil,
|
||||||
expectNoNodeInfo: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "new node with valid max limit",
|
name: "new node with valid max limit",
|
||||||
@ -517,7 +511,6 @@ func TestRemoveNodeInfo(t *testing.T) {
|
|||||||
),
|
),
|
||||||
inputTopology: nil,
|
inputTopology: nil,
|
||||||
inputNodeID: "com.example.csi/csi-node1",
|
inputNodeID: "com.example.csi/csi-node1",
|
||||||
expectNoNodeInfo: true,
|
|
||||||
expectedVolumeLimit: 0,
|
expectedVolumeLimit: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -525,9 +518,9 @@ func TestRemoveNodeInfo(t *testing.T) {
|
|||||||
test(t, false /* addNodeInfo */, true /* csiNodeInfoEnabled */, testcases)
|
test(t, false /* addNodeInfo */, true /* csiNodeInfoEnabled */, testcases)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestRemoveNodeInfo tests RemoveNodeInfo with various existing Node objects and CSINodeInfo
|
// TestUninstallCSIDriver tests UninstallCSIDriver with various existing Node objects and CSINodeInfo
|
||||||
// feature disabled.
|
// feature disabled.
|
||||||
func TestRemoveNodeInfo_CSINodeInfoDisabled(t *testing.T) {
|
func TestUninstallCSIDriver_CSINodeInfoDisabled(t *testing.T) {
|
||||||
testcases := []testcase{
|
testcases := []testcase{
|
||||||
{
|
{
|
||||||
name: "empty node",
|
name: "empty node",
|
||||||
@ -562,7 +555,7 @@ func TestRemoveNodeInfo_CSINodeInfoDisabled(t *testing.T) {
|
|||||||
test(t, false /* addNodeInfo */, false /* csiNodeInfoEnabled */, testcases)
|
test(t, false /* addNodeInfo */, false /* csiNodeInfoEnabled */, testcases)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddNodeInfoExistingAnnotation(t *testing.T) {
|
func TestInstallCSIDriverExistingAnnotation(t *testing.T) {
|
||||||
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSINodeInfo, true)()
|
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSINodeInfo, true)()
|
||||||
|
|
||||||
driverName := "com.example.csi/driver1"
|
driverName := "com.example.csi/driver1"
|
||||||
@ -573,7 +566,7 @@ func TestAddNodeInfoExistingAnnotation(t *testing.T) {
|
|||||||
existingNode *v1.Node
|
existingNode *v1.Node
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "pre-existing info about the same driver in node, but no CSINodeInfo",
|
name: "pre-existing info about the same driver in node, but empty CSINodeInfo",
|
||||||
existingNode: generateNode(
|
existingNode: generateNode(
|
||||||
nodeIDMap{
|
nodeIDMap{
|
||||||
"com.example.csi/driver1": "com.example.csi/csi-node1",
|
"com.example.csi/driver1": "com.example.csi/csi-node1",
|
||||||
@ -581,7 +574,7 @@ func TestAddNodeInfoExistingAnnotation(t *testing.T) {
|
|||||||
nil /* labels */, nil /*capacity*/),
|
nil /* labels */, nil /*capacity*/),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pre-existing info about a different driver in node, but no CSINodeInfo",
|
name: "pre-existing info about a different driver in node, but empty CSINodeInfo",
|
||||||
existingNode: generateNode(
|
existingNode: generateNode(
|
||||||
nodeIDMap{
|
nodeIDMap{
|
||||||
"net.example.storage/other-driver": "net.example.storage/test-node",
|
"net.example.storage/other-driver": "net.example.storage/test-node",
|
||||||
@ -613,9 +606,14 @@ func TestAddNodeInfoExistingAnnotation(t *testing.T) {
|
|||||||
nim := NewNodeInfoManager(types.NodeName(nodeName), host)
|
nim := NewNodeInfoManager(types.NodeName(nodeName), host)
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
err = nim.AddNodeInfo(driverName, nodeID, 0 /* maxVolumeLimit */, nil) // TODO test maxVolumeLimit
|
_, err = nim.CreateCSINodeInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("expected no error from AddNodeInfo call but got: %v", err)
|
t.Errorf("expected no error from creating CSINodeinfo but got: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = nim.InstallCSIDriver(driverName, nodeID, 0 /* maxVolumeLimit */, nil) // TODO test maxVolumeLimit
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("expected no error from InstallCSIDriver call but got: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,14 +624,15 @@ func TestAddNodeInfoExistingAnnotation(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(nodeInfo.CSIDrivers) != 1 {
|
if len(nodeInfo.Spec.Drivers) != 1 || len(nodeInfo.Status.Drivers) != 1 {
|
||||||
t.Errorf("expected 1 CSIDriverInfo entry but got: %d", len(nodeInfo.CSIDrivers))
|
t.Errorf("expected 1 CSIDriverInfoSpec and 1 CSIDriverInfoStatus entry but got: %d, %d",
|
||||||
|
len(nodeInfo.Spec.Drivers), len(nodeInfo.Status.Drivers))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
driver := nodeInfo.CSIDrivers[0]
|
driver := nodeInfo.Spec.Drivers[0]
|
||||||
if driver.Driver != driverName || driver.NodeID != nodeID {
|
if driver.Name != driverName || driver.NodeID != nodeID {
|
||||||
t.Errorf("expected Driver to be %q and NodeID to be %q, but got: %q:%q", driverName, nodeID, driver.Driver, driver.NodeID)
|
t.Errorf("expected Driver to be %q and NodeID to be %q, but got: %q:%q", driverName, nodeID, driver.Name, driver.NodeID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -669,28 +668,29 @@ func test(t *testing.T, addNodeInfo bool, csiNodeInfoEnabled bool, testcases []t
|
|||||||
nim := NewNodeInfoManager(types.NodeName(nodeName), host)
|
nim := NewNodeInfoManager(types.NodeName(nodeName), host)
|
||||||
|
|
||||||
//// Act
|
//// Act
|
||||||
|
nim.CreateCSINodeInfo()
|
||||||
if addNodeInfo {
|
if addNodeInfo {
|
||||||
err = nim.AddNodeInfo(tc.driverName, tc.inputNodeID, tc.inputVolumeLimit, tc.inputTopology)
|
err = nim.InstallCSIDriver(tc.driverName, tc.inputNodeID, tc.inputVolumeLimit, tc.inputTopology)
|
||||||
} else {
|
} else {
|
||||||
err = nim.RemoveNodeInfo(tc.driverName)
|
err = nim.UninstallCSIDriver(tc.driverName)
|
||||||
}
|
}
|
||||||
|
|
||||||
//// Assert
|
//// Assert
|
||||||
if tc.expectFail {
|
if tc.expectFail {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("expected an error from AddNodeInfo call but got none")
|
t.Errorf("expected an error from InstallCSIDriver call but got none")
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
t.Errorf("expected no error from AddNodeInfo call but got: %v", err)
|
t.Errorf("expected no error from InstallCSIDriver call but got: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
actions := client.Actions()
|
actions := client.Actions()
|
||||||
|
|
||||||
var node *v1.Node
|
var node *v1.Node
|
||||||
if hasPatchAction(actions) {
|
if action := hasPatchAction(actions); action != nil {
|
||||||
node, err = applyNodeStatusPatch(tc.existingNode, actions[1].(clienttesting.PatchActionImpl).GetPatch())
|
node, err = applyNodeStatusPatch(tc.existingNode, action.(clienttesting.PatchActionImpl).GetPatch())
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
} else {
|
} else {
|
||||||
node, err = client.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{})
|
node, err = client.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{})
|
||||||
@ -710,6 +710,7 @@ func test(t *testing.T, addNodeInfo bool, csiNodeInfoEnabled bool, testcases []t
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Node ID annotation
|
// Node ID annotation
|
||||||
|
foundInNode := false
|
||||||
annNodeID, ok := node.Annotations[annotationKeyNodeID]
|
annNodeID, ok := node.Annotations[annotationKeyNodeID]
|
||||||
if ok {
|
if ok {
|
||||||
if tc.expectedNodeIDMap == nil {
|
if tc.expectedNodeIDMap == nil {
|
||||||
@ -723,6 +724,8 @@ func test(t *testing.T, addNodeInfo bool, csiNodeInfoEnabled bool, testcases []t
|
|||||||
|
|
||||||
if !helper.Semantic.DeepEqual(actualNodeIDs, tc.expectedNodeIDMap) {
|
if !helper.Semantic.DeepEqual(actualNodeIDs, tc.expectedNodeIDMap) {
|
||||||
t.Errorf("expected annotation %v; got: %v", tc.expectedNodeIDMap, actualNodeIDs)
|
t.Errorf("expected annotation %v; got: %v", tc.expectedNodeIDMap, actualNodeIDs)
|
||||||
|
} else {
|
||||||
|
foundInNode = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -739,25 +742,36 @@ func test(t *testing.T, addNodeInfo bool, csiNodeInfoEnabled bool, testcases []t
|
|||||||
|
|
||||||
/* CSINodeInfo validation */
|
/* CSINodeInfo validation */
|
||||||
nodeInfo, err := csiClient.Csi().CSINodeInfos().Get(nodeName, metav1.GetOptions{})
|
nodeInfo, err := csiClient.Csi().CSINodeInfos().Get(nodeName, metav1.GetOptions{})
|
||||||
if tc.expectNoNodeInfo && errors.IsNotFound(err) {
|
if err != nil {
|
||||||
continue
|
|
||||||
} else if err != nil {
|
|
||||||
t.Errorf("error getting CSINodeInfo: %v", err)
|
t.Errorf("error getting CSINodeInfo: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract node IDs and topology keys
|
// Extract node IDs and topology keys
|
||||||
|
|
||||||
|
availableDrivers := sets.String{}
|
||||||
actualNodeIDs := make(map[string]string)
|
actualNodeIDs := make(map[string]string)
|
||||||
actualTopologyKeys := make(map[string]sets.String)
|
actualTopologyKeys := make(map[string]sets.String)
|
||||||
for _, driver := range nodeInfo.CSIDrivers {
|
for _, driver := range nodeInfo.Status.Drivers {
|
||||||
actualNodeIDs[driver.Driver] = driver.NodeID
|
if driver.Available {
|
||||||
actualTopologyKeys[driver.Driver] = sets.NewString(driver.TopologyKeys...)
|
availableDrivers.Insert(driver.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
for _, driver := range nodeInfo.Spec.Drivers {
|
||||||
|
if availableDrivers.Has(driver.Name) {
|
||||||
|
actualNodeIDs[driver.Name] = driver.NodeID
|
||||||
|
actualTopologyKeys[driver.Name] = sets.NewString(driver.TopologyKeys...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node IDs
|
// Node IDs
|
||||||
|
// No need to check if Node ID found in NodeInfo if it was present in the NodeID
|
||||||
|
if !foundInNode {
|
||||||
if !helper.Semantic.DeepEqual(actualNodeIDs, tc.expectedNodeIDMap) {
|
if !helper.Semantic.DeepEqual(actualNodeIDs, tc.expectedNodeIDMap) {
|
||||||
t.Errorf("expected node IDs %v from CSINodeInfo; got: %v", tc.expectedNodeIDMap, actualNodeIDs)
|
t.Errorf("expected node IDs %v from CSINodeInfo; got: %v", tc.expectedNodeIDMap, actualNodeIDs)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Topology keys
|
// Topology keys
|
||||||
if !helper.Semantic.DeepEqual(actualTopologyKeys, tc.expectedTopologyMap) {
|
if !helper.Semantic.DeepEqual(actualTopologyKeys, tc.expectedTopologyMap) {
|
||||||
@ -802,22 +816,34 @@ func generateNode(nodeIDs, labels map[string]string, capacity map[v1.ResourceNam
|
|||||||
}
|
}
|
||||||
|
|
||||||
func generateNodeInfo(nodeIDs map[string]string, topologyKeys map[string][]string) *csiv1alpha1.CSINodeInfo {
|
func generateNodeInfo(nodeIDs map[string]string, topologyKeys map[string][]string) *csiv1alpha1.CSINodeInfo {
|
||||||
var drivers []csiv1alpha1.CSIDriverInfo
|
driverInfoSpecs := []csiv1alpha1.CSIDriverInfoSpec{}
|
||||||
|
driverInfoStatuses := []csiv1alpha1.CSIDriverInfoStatus{}
|
||||||
for k, nodeID := range nodeIDs {
|
for k, nodeID := range nodeIDs {
|
||||||
d := csiv1alpha1.CSIDriverInfo{
|
dspec := csiv1alpha1.CSIDriverInfoSpec{
|
||||||
Driver: k,
|
Name: k,
|
||||||
NodeID: nodeID,
|
NodeID: nodeID,
|
||||||
}
|
}
|
||||||
if top, exists := topologyKeys[k]; exists {
|
dstatus := csiv1alpha1.CSIDriverInfoStatus{
|
||||||
d.TopologyKeys = top
|
Name: k,
|
||||||
|
Available: true,
|
||||||
|
VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree,
|
||||||
}
|
}
|
||||||
drivers = append(drivers, d)
|
if top, exists := topologyKeys[k]; exists {
|
||||||
|
dspec.TopologyKeys = top
|
||||||
|
}
|
||||||
|
driverInfoSpecs = append(driverInfoSpecs, dspec)
|
||||||
|
driverInfoStatuses = append(driverInfoStatuses, dstatus)
|
||||||
}
|
}
|
||||||
return &csiv1alpha1.CSINodeInfo{
|
return &csiv1alpha1.CSINodeInfo{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "node1",
|
Name: "node1",
|
||||||
},
|
},
|
||||||
CSIDrivers: drivers,
|
Spec: csiv1alpha1.CSINodeInfoSpec{
|
||||||
|
Drivers: driverInfoSpecs,
|
||||||
|
},
|
||||||
|
Status: csiv1alpha1.CSINodeInfoStatus{
|
||||||
|
Drivers: driverInfoStatuses,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,11 +864,11 @@ func applyNodeStatusPatch(originalNode *v1.Node, patch []byte) (*v1.Node, error)
|
|||||||
return updatedNode, nil
|
return updatedNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasPatchAction(actions []clienttesting.Action) bool {
|
func hasPatchAction(actions []clienttesting.Action) clienttesting.Action {
|
||||||
for _, action := range actions {
|
for _, action := range actions {
|
||||||
if action.GetVerb() == "patch" {
|
if action.GetVerb() == "patch" {
|
||||||
return true
|
return action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
@ -216,25 +217,47 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
|||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "mynode",
|
Name: "mynode",
|
||||||
},
|
},
|
||||||
CSIDrivers: []csiv1alpha1.CSIDriverInfo{
|
Spec: csiv1alpha1.CSINodeInfoSpec{
|
||||||
|
Drivers: []csiv1alpha1.CSIDriverInfoSpec{
|
||||||
{
|
{
|
||||||
Driver: "com.example.csi/mydriver",
|
Name: "com.example.csi/mydriver",
|
||||||
NodeID: "com.example.csi/mynode",
|
NodeID: "com.example.csi/mynode",
|
||||||
TopologyKeys: []string{"com.example.csi/zone"},
|
TopologyKeys: []string{"com.example.csi/zone"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
Status: csiv1alpha1.CSINodeInfoStatus{
|
||||||
|
Drivers: []csiv1alpha1.CSIDriverInfoStatus{
|
||||||
|
{
|
||||||
|
Name: "com.example.csi/mydriver",
|
||||||
|
Available: true,
|
||||||
|
VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
nodeInfoWrongName = &csiv1alpha1.CSINodeInfo{
|
nodeInfoWrongName = &csiv1alpha1.CSINodeInfo{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
},
|
},
|
||||||
CSIDrivers: []csiv1alpha1.CSIDriverInfo{
|
Spec: csiv1alpha1.CSINodeInfoSpec{
|
||||||
|
Drivers: []csiv1alpha1.CSIDriverInfoSpec{
|
||||||
{
|
{
|
||||||
Driver: "com.example.csi/mydriver",
|
Name: "com.example.csi/mydriver",
|
||||||
NodeID: "com.example.csi/foo",
|
NodeID: "com.example.csi/foo",
|
||||||
TopologyKeys: []string{"com.example.csi/zone"},
|
TopologyKeys: []string{"com.example.csi/zone"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
Status: csiv1alpha1.CSINodeInfoStatus{
|
||||||
|
Drivers: []csiv1alpha1.CSIDriverInfoStatus{
|
||||||
|
{
|
||||||
|
Name: "com.example.csi/mydriver",
|
||||||
|
Available: true,
|
||||||
|
VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
noExistingPodsIndex = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil)
|
noExistingPodsIndex = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil)
|
||||||
|
52
staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1/README.md
Normal file
52
staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1/README.md
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# CSINodeInfo and CSIDriverInfo Usage and Lifecycle
|
||||||
|
|
||||||
|
CSINodeInfo is an API object representing CSI Information at the Node level.
|
||||||
|
CSINodeInfo contains a Spec and a Status, each containing Drivers represent the
|
||||||
|
driver spec and status respectively. The CSIDriverInfoSpec represents the
|
||||||
|
specification of the driver and is generally not changed, whereas the
|
||||||
|
CSIDriverInfoStatus represents the current status of the driver and can be
|
||||||
|
updated and reacted to by various components.
|
||||||
|
|
||||||
|
## Who creates it and when
|
||||||
|
|
||||||
|
CSINodeInfo is created by Kubelet when the first CSI Driver is installed to the
|
||||||
|
cluster and it is registered through the Kubelet device registration mechanism.
|
||||||
|
|
||||||
|
## Who updates CSIDriverInfo Spec and when
|
||||||
|
|
||||||
|
The CSIDriverInfoSpec for a driver is created upon installation of the CSI
|
||||||
|
Driver to the cluster and it is registered through the Kubelet device
|
||||||
|
registration mechanism. The spec is populated with information about the driver
|
||||||
|
through the nodeinfomanager (inside Kubelet) and will remain unchanged from then
|
||||||
|
on.
|
||||||
|
|
||||||
|
## Who updates Status and when
|
||||||
|
|
||||||
|
The CSIDriverInfoStatus for the driver is created upon installation of the CSI
|
||||||
|
Driver to the cluster (the same time as the spec) and it is registered through
|
||||||
|
the Kubelet device registration mechanism. The Status contains information about
|
||||||
|
installation and the required Volume Plugin Mechanism of the driver. When the
|
||||||
|
driver is installed/uninstalled through the Kubelet device registration
|
||||||
|
mechanism the Available flag is flipped from true/false respectively. The
|
||||||
|
migration status will also be updated when the flags for migration are set to
|
||||||
|
true/false on the Kubelet for that Driver on that node.
|
||||||
|
|
||||||
|
## Consumers of Status and Spec
|
||||||
|
|
||||||
|
Currently the only consumer of CSINodeInfo/CSIDriverInfo is the
|
||||||
|
csi-external-provisioner. In the future, the Attach Detach Controller (ADC) will
|
||||||
|
need to read this object to determine migration status on a per driver per node
|
||||||
|
basis. The creation of the CSINodeInfo object could possibly race with the
|
||||||
|
Attach/Detach controller as for CSI Migration the controller depend on the
|
||||||
|
existence of the API object for the driver but it will not have been created
|
||||||
|
yet. The ADC is expected to fail (and retry with exponential backoff) the
|
||||||
|
operation if it is expecting the object and it has not yet been created.
|
||||||
|
|
||||||
|
## Creation of CSINodeInfo object on Kubelet startup
|
||||||
|
|
||||||
|
For CSI Migration Alpha we expect any user who turns on the feature has both
|
||||||
|
Kubelet and ADC at a version where the CSINodeInfo's are being created on
|
||||||
|
Kubelet startup. We will not promote the feature to Beta (on by default) until
|
||||||
|
the CSINodeInfo's are being created on Kubelet startup for a 2 version skew to
|
||||||
|
prevent the case where the CSINodeInfo does not exist when the ADC depends on
|
||||||
|
it. This prevents the race described above becoming a permanent bad state.
|
@ -18,6 +18,16 @@ package v1alpha1
|
|||||||
|
|
||||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
// VolumePluginMechanism is the type of mechanism components should use for volume operations
|
||||||
|
type VolumePluginMechanism string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// VolumePluginMechanismInTree means components should use the in-tree plugin for volume operations
|
||||||
|
VolumePluginMechanismInTree VolumePluginMechanism = "in-tree"
|
||||||
|
// VolumePluginMechanismCSI means components should use the CSI Driver for volume operations
|
||||||
|
VolumePluginMechanismCSI VolumePluginMechanism = "csi"
|
||||||
|
)
|
||||||
|
|
||||||
// +genclient
|
// +genclient
|
||||||
// +genclient:nonNamespaced
|
// +genclient:nonNamespaced
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
@ -91,18 +101,56 @@ type CSINodeInfo struct {
|
|||||||
// metadata.name must be the Kubernetes node name.
|
// metadata.name must be the Kubernetes node name.
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
// List of CSI drivers running on the node and their properties.
|
// spec is the specification of CSINodeInfo
|
||||||
// +patchMergeKey=driver
|
Spec CSINodeInfoSpec `json:"spec"`
|
||||||
// +patchStrategy=merge
|
|
||||||
CSIDrivers []CSIDriverInfo `json:"csiDrivers" patchStrategy:"merge" patchMergeKey:"driver"`
|
// status is the current status of CSINodeInfo
|
||||||
|
Status CSINodeInfoStatus `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CSIDriverInfo contains information about one CSI driver installed on a node.
|
// CSINodeInfoSpec holds information about the specification of all CSI drivers installed on a node
|
||||||
type CSIDriverInfo struct {
|
type CSINodeInfoSpec struct {
|
||||||
// driver is the name of the CSI driver that this object refers to.
|
// drivers is a list of specifications of CSIDriverInfo
|
||||||
|
// +patchMergeKey=name
|
||||||
|
// +patchStrategy=merge
|
||||||
|
Drivers []CSIDriverInfoSpec `json:"drivers" patchStrategy:"merge" patchMergeKey:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSINodeInfoStatus holds information about the status of all CSI drivers installed on a node
|
||||||
|
type CSINodeInfoStatus struct {
|
||||||
|
// drivers is a list of the statuses of CSIDriverInfo
|
||||||
|
// +patchMergeKey=name
|
||||||
|
// +patchStrategy=merge
|
||||||
|
Drivers []CSIDriverInfoStatus `json:"drivers" patchStrategy:"merge" patchMergeKey:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSIDriverInfoStatus holds information about the status of one CSI driver installed on a node
|
||||||
|
type CSIDriverInfoStatus struct {
|
||||||
|
// name 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
|
// This MUST be the same name returned by the CSI GetPluginName() call for
|
||||||
// that driver.
|
// that driver.
|
||||||
Driver string `json:"driver"`
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// available is a boolean representing whether the driver has been installed
|
||||||
|
// on this node or not.
|
||||||
|
Available bool `json:"available"`
|
||||||
|
|
||||||
|
// volumePluginMechanism announces what mechanism underlies volume plugins.
|
||||||
|
// It is set by Kubelet. It is used by the attach/detach controller, which
|
||||||
|
// needs to know how to perform attachments. The allowed values are:
|
||||||
|
// * "in-tree": the volume operation (e.g., attach/detach) ought to be
|
||||||
|
// directly performed by the attach/detach controller.
|
||||||
|
// * "csi-plugin": the attach/detach controller ought to request
|
||||||
|
// the csi plugin to perform the volume operation rather than perform it directly.
|
||||||
|
VolumePluginMechanism VolumePluginMechanism `json:"volumePluginMechanism"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSIDriverInfoSpec holds information about the specification of one CSI driver installed on a node
|
||||||
|
type CSIDriverInfoSpec struct {
|
||||||
|
// name 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"`
|
||||||
|
|
||||||
// nodeID of the node from the driver point of view.
|
// nodeID of the node from the driver point of view.
|
||||||
// This field enables Kubernetes to communicate with storage systems that do
|
// This field enables Kubernetes to communicate with storage systems that do
|
||||||
|
@ -52,7 +52,7 @@ func (in *CSIDriver) DeepCopyObject() runtime.Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CSIDriverInfo) DeepCopyInto(out *CSIDriverInfo) {
|
func (in *CSIDriverInfoSpec) DeepCopyInto(out *CSIDriverInfoSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.TopologyKeys != nil {
|
if in.TopologyKeys != nil {
|
||||||
in, out := &in.TopologyKeys, &out.TopologyKeys
|
in, out := &in.TopologyKeys, &out.TopologyKeys
|
||||||
@ -62,12 +62,28 @@ func (in *CSIDriverInfo) DeepCopyInto(out *CSIDriverInfo) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriverInfo.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriverInfoSpec.
|
||||||
func (in *CSIDriverInfo) DeepCopy() *CSIDriverInfo {
|
func (in *CSIDriverInfoSpec) DeepCopy() *CSIDriverInfoSpec {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := new(CSIDriverInfo)
|
out := new(CSIDriverInfoSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CSIDriverInfoStatus) DeepCopyInto(out *CSIDriverInfoStatus) {
|
||||||
|
*out = *in
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriverInfoStatus.
|
||||||
|
func (in *CSIDriverInfoStatus) DeepCopy() *CSIDriverInfoStatus {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CSIDriverInfoStatus)
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
@ -136,13 +152,8 @@ func (in *CSINodeInfo) DeepCopyInto(out *CSINodeInfo) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
if in.CSIDrivers != nil {
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
in, out := &in.CSIDrivers, &out.CSIDrivers
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
*out = make([]CSIDriverInfo, len(*in))
|
|
||||||
for i := range *in {
|
|
||||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,3 +207,47 @@ func (in *CSINodeInfoList) DeepCopyObject() runtime.Object {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CSINodeInfoSpec) DeepCopyInto(out *CSINodeInfoSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.Drivers != nil {
|
||||||
|
in, out := &in.Drivers, &out.Drivers
|
||||||
|
*out = make([]CSIDriverInfoSpec, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeInfoSpec.
|
||||||
|
func (in *CSINodeInfoSpec) DeepCopy() *CSINodeInfoSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CSINodeInfoSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CSINodeInfoStatus) DeepCopyInto(out *CSINodeInfoStatus) {
|
||||||
|
*out = *in
|
||||||
|
if in.Drivers != nil {
|
||||||
|
in, out := &in.Drivers, &out.Drivers
|
||||||
|
*out = make([]CSIDriverInfoStatus, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeInfoStatus.
|
||||||
|
func (in *CSINodeInfoStatus) DeepCopy() *CSINodeInfoStatus {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CSINodeInfoStatus)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
@ -37,6 +37,7 @@ type CSINodeInfosGetter interface {
|
|||||||
type CSINodeInfoInterface interface {
|
type CSINodeInfoInterface interface {
|
||||||
Create(*v1alpha1.CSINodeInfo) (*v1alpha1.CSINodeInfo, error)
|
Create(*v1alpha1.CSINodeInfo) (*v1alpha1.CSINodeInfo, error)
|
||||||
Update(*v1alpha1.CSINodeInfo) (*v1alpha1.CSINodeInfo, error)
|
Update(*v1alpha1.CSINodeInfo) (*v1alpha1.CSINodeInfo, error)
|
||||||
|
UpdateStatus(*v1alpha1.CSINodeInfo) (*v1alpha1.CSINodeInfo, error)
|
||||||
Delete(name string, options *v1.DeleteOptions) error
|
Delete(name string, options *v1.DeleteOptions) error
|
||||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||||
Get(name string, options v1.GetOptions) (*v1alpha1.CSINodeInfo, error)
|
Get(name string, options v1.GetOptions) (*v1alpha1.CSINodeInfo, error)
|
||||||
@ -113,6 +114,21 @@ func (c *cSINodeInfos) Update(cSINodeInfo *v1alpha1.CSINodeInfo) (result *v1alph
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateStatus was generated because the type contains a Status member.
|
||||||
|
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||||
|
|
||||||
|
func (c *cSINodeInfos) UpdateStatus(cSINodeInfo *v1alpha1.CSINodeInfo) (result *v1alpha1.CSINodeInfo, err error) {
|
||||||
|
result = &v1alpha1.CSINodeInfo{}
|
||||||
|
err = c.client.Put().
|
||||||
|
Resource("csinodeinfos").
|
||||||
|
Name(cSINodeInfo.Name).
|
||||||
|
SubResource("status").
|
||||||
|
Body(cSINodeInfo).
|
||||||
|
Do().
|
||||||
|
Into(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Delete takes name of the cSINodeInfo and deletes it. Returns an error if one occurs.
|
// Delete takes name of the cSINodeInfo and deletes it. Returns an error if one occurs.
|
||||||
func (c *cSINodeInfos) Delete(name string, options *v1.DeleteOptions) error {
|
func (c *cSINodeInfos) Delete(name string, options *v1.DeleteOptions) error {
|
||||||
return c.client.Delete().
|
return c.client.Delete().
|
||||||
|
@ -94,6 +94,17 @@ func (c *FakeCSINodeInfos) Update(cSINodeInfo *v1alpha1.CSINodeInfo) (result *v1
|
|||||||
return obj.(*v1alpha1.CSINodeInfo), err
|
return obj.(*v1alpha1.CSINodeInfo), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateStatus was generated because the type contains a Status member.
|
||||||
|
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||||
|
func (c *FakeCSINodeInfos) UpdateStatus(cSINodeInfo *v1alpha1.CSINodeInfo) (*v1alpha1.CSINodeInfo, error) {
|
||||||
|
obj, err := c.Fake.
|
||||||
|
Invokes(testing.NewRootUpdateSubresourceAction(csinodeinfosResource, "status", cSINodeInfo), &v1alpha1.CSINodeInfo{})
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj.(*v1alpha1.CSINodeInfo), err
|
||||||
|
}
|
||||||
|
|
||||||
// Delete takes name of the cSINodeInfo and deletes it. Returns an error if one occurs.
|
// Delete takes name of the cSINodeInfo and deletes it. Returns an error if one occurs.
|
||||||
func (c *FakeCSINodeInfos) Delete(name string, options *v1.DeleteOptions) error {
|
func (c *FakeCSINodeInfos) Delete(name string, options *v1.DeleteOptions) error {
|
||||||
_, err := c.Fake.
|
_, err := c.Fake.
|
||||||
|
@ -13,11 +13,15 @@ spec:
|
|||||||
validation:
|
validation:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
properties:
|
properties:
|
||||||
csiDrivers:
|
spec:
|
||||||
description: List of CSI drivers running on the node and their properties.
|
description: Specification of CSINodeInfo
|
||||||
|
properties:
|
||||||
|
drivers:
|
||||||
|
description: List of CSI drivers running on the node and their specs.
|
||||||
|
type: array
|
||||||
items:
|
items:
|
||||||
properties:
|
properties:
|
||||||
driver:
|
name:
|
||||||
description: The CSI driver that this object refers to.
|
description: The CSI driver that this object refers to.
|
||||||
type: string
|
type: string
|
||||||
nodeID:
|
nodeID:
|
||||||
@ -28,5 +32,23 @@ spec:
|
|||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
status:
|
||||||
|
description: Status of CSINodeInfo
|
||||||
|
properties:
|
||||||
|
drivers:
|
||||||
|
description: List of CSI drivers running on the node and their statuses.
|
||||||
type: array
|
type: array
|
||||||
|
items:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: The CSI driver that this object refers to.
|
||||||
|
type: string
|
||||||
|
available:
|
||||||
|
description: Whether the CSI driver is installed.
|
||||||
|
type: boolean
|
||||||
|
volumePluginMechanism:
|
||||||
|
description: Indicates to external components the required mechanism
|
||||||
|
to use for any in-tree plugins replaced by this driver.
|
||||||
|
pattern: in-tree|csi
|
||||||
|
type: string
|
||||||
version: v1alpha1
|
version: v1alpha1
|
||||||
|
@ -420,13 +420,24 @@ func TestNodeAuthorizer(t *testing.T) {
|
|||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "node1",
|
Name: "node1",
|
||||||
},
|
},
|
||||||
CSIDrivers: []csiv1alpha1.CSIDriverInfo{
|
Spec: csiv1alpha1.CSINodeInfoSpec{
|
||||||
|
Drivers: []csiv1alpha1.CSIDriverInfoSpec{
|
||||||
{
|
{
|
||||||
Driver: "com.example.csi/driver1",
|
Name: "com.example.csi/driver1",
|
||||||
NodeID: "com.example.csi/node1",
|
NodeID: "com.example.csi/node1",
|
||||||
TopologyKeys: []string{"com.example.csi/zone"},
|
TopologyKeys: []string{"com.example.csi/zone"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
Status: csiv1alpha1.CSINodeInfoStatus{
|
||||||
|
Drivers: []csiv1alpha1.CSIDriverInfoStatus{
|
||||||
|
{
|
||||||
|
Name: "com.example.csi/driver1",
|
||||||
|
Available: true,
|
||||||
|
VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
_, err := client.CsiV1alpha1().CSINodeInfos().Create(nodeInfo)
|
_, err := client.CsiV1alpha1().CSINodeInfos().Create(nodeInfo)
|
||||||
return err
|
return err
|
||||||
@ -438,13 +449,20 @@ func TestNodeAuthorizer(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
nodeInfo.CSIDrivers = []csiv1alpha1.CSIDriverInfo{
|
nodeInfo.Spec.Drivers = []csiv1alpha1.CSIDriverInfoSpec{
|
||||||
{
|
{
|
||||||
Driver: "com.example.csi/driver1",
|
Name: "com.example.csi/driver1",
|
||||||
NodeID: "com.example.csi/node1",
|
NodeID: "com.example.csi/node1",
|
||||||
TopologyKeys: []string{"com.example.csi/rack"},
|
TopologyKeys: []string{"com.example.csi/rack"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
nodeInfo.Status.Drivers = []csiv1alpha1.CSIDriverInfoStatus{
|
||||||
|
{
|
||||||
|
Name: "com.example.csi/driver1",
|
||||||
|
Available: true,
|
||||||
|
VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree,
|
||||||
|
},
|
||||||
|
}
|
||||||
_, err = client.CsiV1alpha1().CSINodeInfos().Update(nodeInfo)
|
_, err = client.CsiV1alpha1().CSINodeInfos().Update(nodeInfo)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user