Store PVC reference counts in NodeInfo cache

This map will be queried as part of enforcement of the ReadWriteOncePod
access mode for PVCs
This commit is contained in:
Chris Henzie
2021-06-21 12:49:39 -07:00
parent 01819dd322
commit ebc3fdb293
2 changed files with 120 additions and 13 deletions

View File

@@ -387,6 +387,10 @@ type NodeInfo struct {
// state information.
ImageStates map[string]*ImageStateSummary
// PVCRefCounts contains a mapping of PVC names to the number of pods on the node using it.
// Keys are in the format "namespace/name".
PVCRefCounts map[string]int
// Whenever NodeInfo changes, generation is bumped.
// This is used to avoid cloning it if the object didn't change.
Generation int64
@@ -512,6 +516,7 @@ func NewNodeInfo(pods ...*v1.Pod) *NodeInfo {
Generation: nextGeneration(),
UsedPorts: make(HostPortInfo),
ImageStates: make(map[string]*ImageStateSummary),
PVCRefCounts: make(map[string]int),
}
for _, pod := range pods {
ni.AddPod(pod)
@@ -536,6 +541,7 @@ func (n *NodeInfo) Clone() *NodeInfo {
Allocatable: n.Allocatable.Clone(),
UsedPorts: make(HostPortInfo),
ImageStates: n.ImageStates,
PVCRefCounts: n.PVCRefCounts,
Generation: n.Generation,
}
if len(n.Pods) > 0 {
@@ -595,6 +601,7 @@ func (n *NodeInfo) AddPodInfo(podInfo *PodInfo) {
// Consume ports when pods added.
n.updateUsedPorts(podInfo.Pod, true)
n.updatePVCRefCounts(podInfo.Pod, true)
n.Generation = nextGeneration()
}
@@ -672,6 +679,7 @@ func (n *NodeInfo) RemovePod(pod *v1.Pod) error {
// Release ports when remove Pods.
n.updateUsedPorts(pod, false)
n.updatePVCRefCounts(pod, false)
n.Generation = nextGeneration()
n.resetSlicesIfEmpty()
@@ -749,6 +757,25 @@ func (n *NodeInfo) updateUsedPorts(pod *v1.Pod, add bool) {
}
}
// updatePVCRefCounts updates the PVCRefCounts of NodeInfo.
func (n *NodeInfo) updatePVCRefCounts(pod *v1.Pod, add bool) {
for _, v := range pod.Spec.Volumes {
if v.PersistentVolumeClaim == nil {
continue
}
key := pod.Namespace + "/" + v.PersistentVolumeClaim.ClaimName
if add {
n.PVCRefCounts[key] += 1
} else {
n.PVCRefCounts[key] -= 1
if n.PVCRefCounts[key] <= 0 {
delete(n.PVCRefCounts, key)
}
}
}
}
// SetNode sets the overall node information.
func (n *NodeInfo) SetNode(node *v1.Node) {
n.node = node

View File

@@ -211,7 +211,7 @@ type testingMode interface {
Fatalf(format string, args ...interface{})
}
func makeBasePod(t testingMode, nodeName, objName, cpu, mem, extended string, ports []v1.ContainerPort) *v1.Pod {
func makeBasePod(t testingMode, nodeName, objName, cpu, mem, extended string, ports []v1.ContainerPort, volumes []v1.Volume) *v1.Pod {
req := v1.ResourceList{}
if cpu != "" {
req = v1.ResourceList{
@@ -240,6 +240,7 @@ func makeBasePod(t testingMode, nodeName, objName, cpu, mem, extended string, po
Ports: ports,
}},
NodeName: nodeName,
Volumes: volumes,
},
}
}
@@ -247,8 +248,8 @@ func makeBasePod(t testingMode, nodeName, objName, cpu, mem, extended string, po
func TestNewNodeInfo(t *testing.T) {
nodeName := "test-node"
pods := []*v1.Pod{
makeBasePod(t, nodeName, "test-1", "100m", "500", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 80, Protocol: "TCP"}}),
makeBasePod(t, nodeName, "test-2", "200m", "1Ki", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 8080, Protocol: "TCP"}}),
makeBasePod(t, nodeName, "test-1", "100m", "500", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 80, Protocol: "TCP"}}, nil),
makeBasePod(t, nodeName, "test-2", "200m", "1Ki", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 8080, Protocol: "TCP"}}, nil),
}
expected := &NodeInfo{
@@ -275,6 +276,7 @@ func TestNewNodeInfo(t *testing.T) {
},
},
ImageStates: map[string]*ImageStateSummary{},
PVCRefCounts: map[string]int{},
Pods: []*PodInfo{
{
Pod: &v1.Pod{
@@ -367,6 +369,7 @@ func TestNodeInfoClone(t *testing.T) {
},
},
ImageStates: map[string]*ImageStateSummary{},
PVCRefCounts: map[string]int{},
Pods: []*PodInfo{
{
Pod: &v1.Pod{
@@ -440,6 +443,7 @@ func TestNodeInfoClone(t *testing.T) {
},
},
ImageStates: map[string]*ImageStateSummary{},
PVCRefCounts: map[string]int{},
Pods: []*PodInfo{
{
Pod: &v1.Pod{
@@ -548,6 +552,15 @@ func TestNodeInfoAddPod(t *testing.T) {
Overhead: v1.ResourceList{
v1.ResourceCPU: resource.MustParse("500m"),
},
Volumes: []v1.Volume{
{
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: "pvc-1",
},
},
},
},
},
},
{
@@ -578,6 +591,15 @@ func TestNodeInfoAddPod(t *testing.T) {
v1.ResourceCPU: resource.MustParse("500m"),
v1.ResourceMemory: resource.MustParse("500"),
},
Volumes: []v1.Volume{
{
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: "pvc-1",
},
},
},
},
},
},
{
@@ -618,6 +640,15 @@ func TestNodeInfoAddPod(t *testing.T) {
v1.ResourceCPU: resource.MustParse("500m"),
v1.ResourceMemory: resource.MustParse("500"),
},
Volumes: []v1.Volume{
{
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: "pvc-2",
},
},
},
},
},
},
}
@@ -650,6 +681,7 @@ func TestNodeInfoAddPod(t *testing.T) {
},
},
ImageStates: map[string]*ImageStateSummary{},
PVCRefCounts: map[string]int{"node_info_cache_test/pvc-1": 2, "node_info_cache_test/pvc-2": 1},
Pods: []*PodInfo{
{
Pod: &v1.Pod{
@@ -680,6 +712,15 @@ func TestNodeInfoAddPod(t *testing.T) {
Overhead: v1.ResourceList{
v1.ResourceCPU: resource.MustParse("500m"),
},
Volumes: []v1.Volume{
{
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: "pvc-1",
},
},
},
},
},
},
},
@@ -712,6 +753,15 @@ func TestNodeInfoAddPod(t *testing.T) {
v1.ResourceCPU: resource.MustParse("500m"),
v1.ResourceMemory: resource.MustParse("500"),
},
Volumes: []v1.Volume{
{
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: "pvc-1",
},
},
},
},
},
},
},
@@ -754,6 +804,15 @@ func TestNodeInfoAddPod(t *testing.T) {
v1.ResourceCPU: resource.MustParse("500m"),
v1.ResourceMemory: resource.MustParse("500"),
},
Volumes: []v1.Volume{
{
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: "pvc-2",
},
},
},
},
},
},
},
@@ -779,9 +838,10 @@ func TestNodeInfoAddPod(t *testing.T) {
func TestNodeInfoRemovePod(t *testing.T) {
nodeName := "test-node"
pods := []*v1.Pod{
makeBasePod(t, nodeName, "test-1", "100m", "500", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 80, Protocol: "TCP"}}),
makeBasePod(t, nodeName, "test-2", "200m", "1Ki", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 8080, Protocol: "TCP"}}),
makeBasePod(t, nodeName, "test-1", "100m", "500", "",
[]v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 80, Protocol: "TCP"}},
[]v1.Volume{{VolumeSource: v1.VolumeSource{PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ClaimName: "pvc-1"}}}}),
makeBasePod(t, nodeName, "test-2", "200m", "1Ki", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 8080, Protocol: "TCP"}}, nil),
}
// add pod Overhead
@@ -798,7 +858,7 @@ func TestNodeInfoRemovePod(t *testing.T) {
expectedNodeInfo *NodeInfo
}{
{
pod: makeBasePod(t, nodeName, "non-exist", "0", "0", "", []v1.ContainerPort{{}}),
pod: makeBasePod(t, nodeName, "non-exist", "0", "0", "", []v1.ContainerPort{{}}, []v1.Volume{}),
errExpected: true,
expectedNodeInfo: &NodeInfo{
node: &v1.Node{
@@ -829,6 +889,7 @@ func TestNodeInfoRemovePod(t *testing.T) {
},
},
ImageStates: map[string]*ImageStateSummary{},
PVCRefCounts: map[string]int{"node_info_cache_test/pvc-1": 1},
Pods: []*PodInfo{
{
Pod: &v1.Pod{
@@ -860,6 +921,15 @@ func TestNodeInfoRemovePod(t *testing.T) {
v1.ResourceCPU: resource.MustParse("500m"),
v1.ResourceMemory: resource.MustParse("500"),
},
Volumes: []v1.Volume{
{
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: "pvc-1",
},
},
},
},
},
},
},
@@ -929,6 +999,15 @@ func TestNodeInfoRemovePod(t *testing.T) {
v1.ResourceCPU: resource.MustParse("500m"),
v1.ResourceMemory: resource.MustParse("500"),
},
Volumes: []v1.Volume{
{
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: "pvc-1",
},
},
},
},
},
},
errExpected: false,
@@ -960,6 +1039,7 @@ func TestNodeInfoRemovePod(t *testing.T) {
},
},
ImageStates: map[string]*ImageStateSummary{},
PVCRefCounts: map[string]int{},
Pods: []*PodInfo{
{
Pod: &v1.Pod{