Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
a04e8544
Unverified
Commit
a04e8544
authored
Nov 13, 2018
by
k8s-ci-robot
Committed by
GitHub
Nov 13, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #70742 from ddebroy/ddebroy-csinode1
Add validation of CSINodeInfo fields before Create/Update actions
parents
709e6ac3
05759a90
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
347 additions
and
2 deletions
+347
-2
nodeinfomanager.go
pkg/volume/csi/nodeinfomanager/nodeinfomanager.go
+57
-2
nodeinfomanager_test.go
pkg/volume/csi/nodeinfomanager/nodeinfomanager_test.go
+290
-0
No files found.
pkg/volume/csi/nodeinfomanager/nodeinfomanager.go
View file @
a04e8544
...
@@ -21,6 +21,7 @@ package nodeinfomanager // import "k8s.io/kubernetes/pkg/volume/csi/nodeinfomana
...
@@ -21,6 +21,7 @@ package nodeinfomanager // import "k8s.io/kubernetes/pkg/volume/csi/nodeinfomana
import
(
import
(
"encoding/json"
"encoding/json"
"fmt"
"fmt"
"strings"
csipb
"github.com/container-storage-interface/spec/lib/go/csi/v0"
csipb
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"k8s.io/api/core/v1"
"k8s.io/api/core/v1"
...
@@ -458,7 +459,11 @@ func (nim *nodeInfoManager) installDriverToCSINodeInfo(
...
@@ -458,7 +459,11 @@ func (nim *nodeInfoManager) installDriverToCSINodeInfo(
nodeInfo
.
Spec
.
Drivers
=
newDriverSpecs
nodeInfo
.
Spec
.
Drivers
=
newDriverSpecs
nodeInfo
.
Status
.
Drivers
=
newDriverStatuses
nodeInfo
.
Status
.
Drivers
=
newDriverStatuses
_
,
err
:=
csiKubeClient
.
CsiV1alpha1
()
.
CSINodeInfos
()
.
Update
(
nodeInfo
)
err
:=
validateCSINodeInfo
(
nodeInfo
)
if
err
!=
nil
{
return
err
}
_
,
err
=
csiKubeClient
.
CsiV1alpha1
()
.
CSINodeInfos
()
.
Update
(
nodeInfo
)
return
err
// do not wrap error
return
err
// do not wrap error
}
}
...
@@ -494,7 +499,10 @@ func (nim *nodeInfoManager) uninstallDriverFromCSINodeInfo(csiDriverName string)
...
@@ -494,7 +499,10 @@ func (nim *nodeInfoManager) uninstallDriverFromCSINodeInfo(csiDriverName string)
return
nil
return
nil
}
}
// TODO (verult) make sure CSINodeInfo has validation logic to prevent duplicate driver names
err
=
validateCSINodeInfo
(
nodeInfo
)
if
err
!=
nil
{
return
err
}
_
,
updateErr
:=
nodeInfoClient
.
Update
(
nodeInfo
)
_
,
updateErr
:=
nodeInfoClient
.
Update
(
nodeInfo
)
return
updateErr
// do not wrap error
return
updateErr
// do not wrap error
...
@@ -557,3 +565,50 @@ func removeMaxAttachLimit(driverName string) nodeUpdateFunc {
...
@@ -557,3 +565,50 @@ func removeMaxAttachLimit(driverName string) nodeUpdateFunc {
return
node
,
true
,
nil
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
,
", "
))
}
pkg/volume/csi/nodeinfomanager/nodeinfomanager_test.go
View file @
a04e8544
...
@@ -637,6 +637,296 @@ func TestInstallCSIDriverExistingAnnotation(t *testing.T) {
...
@@ -637,6 +637,296 @@ func TestInstallCSIDriverExistingAnnotation(t *testing.T) {
}
}
}
}
func
TestValidateCSINodeInfo
(
t
*
testing
.
T
)
{
testcases
:=
[]
struct
{
name
string
nodeInfo
*
csiv1alpha1
.
CSINodeInfo
expectErr
bool
}{
{
name
:
"multiple drivers with different node IDs, topology keys and status"
,
nodeInfo
:
&
csiv1alpha1
.
CSINodeInfo
{
Spec
:
csiv1alpha1
.
CSINodeInfoSpec
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoSpec
{
{
Name
:
"driver1"
,
NodeID
:
"node1"
,
TopologyKeys
:
[]
string
{
"key1, key2"
},
},
{
Name
:
"driverB"
,
NodeID
:
"nodeA"
,
TopologyKeys
:
[]
string
{
"keyA"
,
"keyB"
},
},
},
},
Status
:
csiv1alpha1
.
CSINodeInfoStatus
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoStatus
{
{
Name
:
"driver1"
,
Available
:
true
,
VolumePluginMechanism
:
"in-tree"
,
},
{
Name
:
"driverB"
,
Available
:
false
,
VolumePluginMechanism
:
"csi"
,
},
},
},
},
expectErr
:
false
,
},
{
name
:
"multiple drivers with same node IDs, topology keys and status"
,
nodeInfo
:
&
csiv1alpha1
.
CSINodeInfo
{
Spec
:
csiv1alpha1
.
CSINodeInfoSpec
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoSpec
{
{
Name
:
"driver1"
,
NodeID
:
"node1"
,
TopologyKeys
:
[]
string
{
"key1"
},
},
{
Name
:
"driver2"
,
NodeID
:
"node1"
,
TopologyKeys
:
[]
string
{
"key1"
},
},
},
},
Status
:
csiv1alpha1
.
CSINodeInfoStatus
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoStatus
{
{
Name
:
"driver1"
,
Available
:
true
,
VolumePluginMechanism
:
"csi"
,
},
{
Name
:
"driver2"
,
Available
:
true
,
VolumePluginMechanism
:
"csi"
,
},
},
},
},
expectErr
:
false
,
},
{
name
:
"duplicate drivers in driver specs"
,
nodeInfo
:
&
csiv1alpha1
.
CSINodeInfo
{
Spec
:
csiv1alpha1
.
CSINodeInfoSpec
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoSpec
{
{
Name
:
"driver1"
,
NodeID
:
"node1"
,
TopologyKeys
:
[]
string
{
"key1"
,
"key2"
},
},
{
Name
:
"driver1"
,
NodeID
:
"nodeX"
,
TopologyKeys
:
[]
string
{
"keyA"
,
"keyB"
},
},
},
},
Status
:
csiv1alpha1
.
CSINodeInfoStatus
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoStatus
{
{
Name
:
"driver1"
,
Available
:
true
,
VolumePluginMechanism
:
"csi"
,
},
},
},
},
expectErr
:
true
,
},
{
name
:
"duplicate drivers in driver statuses"
,
nodeInfo
:
&
csiv1alpha1
.
CSINodeInfo
{
Spec
:
csiv1alpha1
.
CSINodeInfoSpec
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoSpec
{
{
Name
:
"driver1"
,
NodeID
:
"node1"
,
TopologyKeys
:
[]
string
{
"key1"
,
"key2"
},
},
},
},
Status
:
csiv1alpha1
.
CSINodeInfoStatus
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoStatus
{
{
Name
:
"driver1"
,
Available
:
true
,
VolumePluginMechanism
:
"in-tree"
,
},
{
Name
:
"driver1"
,
Available
:
false
,
VolumePluginMechanism
:
"csi"
,
},
},
},
},
expectErr
:
true
,
},
{
name
:
"single driver with duplicate topology keys in driver specs"
,
nodeInfo
:
&
csiv1alpha1
.
CSINodeInfo
{
Spec
:
csiv1alpha1
.
CSINodeInfoSpec
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoSpec
{
{
Name
:
"driver1"
,
NodeID
:
"node1"
,
TopologyKeys
:
[]
string
{
"key1"
,
"key1"
},
},
},
},
Status
:
csiv1alpha1
.
CSINodeInfoStatus
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoStatus
{
{
Name
:
"driver1"
,
Available
:
true
,
VolumePluginMechanism
:
"csi"
,
},
},
},
},
expectErr
:
true
,
},
{
name
:
"multiple drivers with one set of duplicate topology keys in driver specs"
,
nodeInfo
:
&
csiv1alpha1
.
CSINodeInfo
{
Spec
:
csiv1alpha1
.
CSINodeInfoSpec
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoSpec
{
{
Name
:
"driver1"
,
NodeID
:
"node1"
,
TopologyKeys
:
[]
string
{
"key1"
},
},
{
Name
:
"driver2"
,
NodeID
:
"nodeX"
,
TopologyKeys
:
[]
string
{
"keyA"
,
"keyA"
},
},
},
},
Status
:
csiv1alpha1
.
CSINodeInfoStatus
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoStatus
{
{
Name
:
"driver1"
,
Available
:
true
,
VolumePluginMechanism
:
"csi"
,
},
{
Name
:
"driver2"
,
Available
:
true
,
VolumePluginMechanism
:
"csi"
,
},
},
},
},
expectErr
:
true
,
},
{
name
:
"mismatch between drivers in specs and status (null intersection)"
,
nodeInfo
:
&
csiv1alpha1
.
CSINodeInfo
{
Spec
:
csiv1alpha1
.
CSINodeInfoSpec
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoSpec
{
{
Name
:
"driver1"
,
NodeID
:
"node1"
,
TopologyKeys
:
[]
string
{
"key1"
},
},
{
Name
:
"driver2"
,
NodeID
:
"nodeX"
,
TopologyKeys
:
[]
string
{
"keyA"
,
"keyA"
},
},
},
},
Status
:
csiv1alpha1
.
CSINodeInfoStatus
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoStatus
{
{
Name
:
"driver3"
,
Available
:
true
,
VolumePluginMechanism
:
"csi"
,
},
},
},
},
expectErr
:
true
,
},
{
name
:
"mismatch between drivers in specs and status (specs superset of status)"
,
nodeInfo
:
&
csiv1alpha1
.
CSINodeInfo
{
Spec
:
csiv1alpha1
.
CSINodeInfoSpec
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoSpec
{
{
Name
:
"driver1"
,
NodeID
:
"node1"
,
TopologyKeys
:
[]
string
{
"key1"
},
},
{
Name
:
"driver2"
,
NodeID
:
"nodeX"
,
TopologyKeys
:
[]
string
{
"keyA"
,
"keyA"
},
},
},
},
Status
:
csiv1alpha1
.
CSINodeInfoStatus
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoStatus
{
{
Name
:
"driver1"
,
Available
:
true
,
VolumePluginMechanism
:
"csi"
,
},
},
},
},
expectErr
:
true
,
},
{
name
:
"mismatch between drivers in specs and status (specs subset of status)"
,
nodeInfo
:
&
csiv1alpha1
.
CSINodeInfo
{
Spec
:
csiv1alpha1
.
CSINodeInfoSpec
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoSpec
{
{
Name
:
"driver1"
,
NodeID
:
"node1"
,
TopologyKeys
:
[]
string
{
"key1"
},
},
},
},
Status
:
csiv1alpha1
.
CSINodeInfoStatus
{
Drivers
:
[]
csiv1alpha1
.
CSIDriverInfoStatus
{
{
Name
:
"driver1"
,
Available
:
true
,
VolumePluginMechanism
:
"csi"
,
},
{
Name
:
"driver2"
,
Available
:
true
,
VolumePluginMechanism
:
"csi"
,
},
},
},
},
expectErr
:
true
,
},
}
for
_
,
tc
:=
range
testcases
{
t
.
Logf
(
"test case: %q"
,
tc
.
name
)
err
:=
validateCSINodeInfo
(
tc
.
nodeInfo
)
if
err
!=
nil
&&
!
tc
.
expectErr
{
t
.
Errorf
(
"expected no errors from validateCSINodeInfo but got error %v"
,
err
)
}
if
err
==
nil
&&
tc
.
expectErr
{
t
.
Errorf
(
"expected error from validateCSINodeInfo but got no errors"
)
}
}
}
func
test
(
t
*
testing
.
T
,
addNodeInfo
bool
,
csiNodeInfoEnabled
bool
,
testcases
[]
testcase
)
{
func
test
(
t
*
testing
.
T
,
addNodeInfo
bool
,
csiNodeInfoEnabled
bool
,
testcases
[]
testcase
)
{
defer
utilfeaturetesting
.
SetFeatureGateDuringTest
(
t
,
utilfeature
.
DefaultFeatureGate
,
features
.
CSINodeInfo
,
csiNodeInfoEnabled
)()
defer
utilfeaturetesting
.
SetFeatureGateDuringTest
(
t
,
utilfeature
.
DefaultFeatureGate
,
features
.
CSINodeInfo
,
csiNodeInfoEnabled
)()
defer
utilfeaturetesting
.
SetFeatureGateDuringTest
(
t
,
utilfeature
.
DefaultFeatureGate
,
features
.
AttachVolumeLimit
,
true
)()
defer
utilfeaturetesting
.
SetFeatureGateDuringTest
(
t
,
utilfeature
.
DefaultFeatureGate
,
features
.
AttachVolumeLimit
,
true
)()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment