mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-05 23:47:50 +00:00
Merge pull request #64226 from ddebroy/ddebroy-affinity1
Automatic merge from submit-queue (batch tested with PRs 64226, 65880). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Populate NodeAffinity on top of labels for cloud based PersistentVolumes **What this PR does / why we need it**: This PR populates the NodeAffinity field (on top of the existing labels) for PVs backed by cloud providers like EC2 EBS and GCE PD. **Special notes for your reviewer**: Related to https://github.com/kubernetes/kubernetes/pull/63232 Sample `describe pv` output for EBS with node affinity field populated: ``` kubectl describe pv pv0001 Name: pv0001 Labels: failure-domain.beta.kubernetes.io/region=us-west-2 failure-domain.beta.kubernetes.io/zone=us-west-2a Annotations: <none> Finalizers: [kubernetes.io/pv-protection] StorageClass: Status: Available Claim: Reclaim Policy: Retain Access Modes: RWO Capacity: 5Gi Node Affinity: Required Terms: Term 0: failure-domain.beta.kubernetes.io/zone in [us-west-2a] failure-domain.beta.kubernetes.io/region in [us-west-2] Message: Source: Type: AWSElasticBlockStore (a Persistent Disk resource in AWS) VolumeID: vol-00cf03a068c62cbe6 FSType: ext4 Partition: 0 ReadOnly: false Events: <none> ``` /sig storage /assign @msau42 **Release note**: ```NONE```
This commit is contained in:
@@ -283,6 +283,20 @@ func NodeSelectorRequirementsAsFieldSelector(nsm []v1.NodeSelectorRequirement) (
|
||||
return fields.AndSelectors(selectors...), nil
|
||||
}
|
||||
|
||||
// NodeSelectorRequirementKeysExistInNodeSelectorTerms checks if a NodeSelectorTerm with key is already specified in terms
|
||||
func NodeSelectorRequirementKeysExistInNodeSelectorTerms(reqs []v1.NodeSelectorRequirement, terms []v1.NodeSelectorTerm) bool {
|
||||
for _, req := range reqs {
|
||||
for _, term := range terms {
|
||||
for _, r := range term.MatchExpressions {
|
||||
if r.Key == req.Key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MatchNodeSelectorTerms checks whether the node labels and fields match node selector terms in ORed;
|
||||
// nil or empty term matches no objects.
|
||||
func MatchNodeSelectorTerms(
|
||||
|
||||
@@ -968,3 +968,193 @@ func TestMatchTopologySelectorTerms(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeSelectorRequirementKeyExistsInNodeSelectorTerms(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
reqs []v1.NodeSelectorRequirement
|
||||
terms []v1.NodeSelectorTerm
|
||||
exists bool
|
||||
}{
|
||||
{
|
||||
name: "empty set of keys in empty set of terms",
|
||||
reqs: []v1.NodeSelectorRequirement{},
|
||||
terms: []v1.NodeSelectorTerm{},
|
||||
exists: false,
|
||||
},
|
||||
{
|
||||
name: "key existence in terms with all keys specified",
|
||||
reqs: []v1.NodeSelectorRequirement{
|
||||
{
|
||||
Key: "key1",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value1"},
|
||||
},
|
||||
{
|
||||
Key: "key2",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value2"},
|
||||
},
|
||||
},
|
||||
terms: []v1.NodeSelectorTerm{
|
||||
{
|
||||
MatchExpressions: []v1.NodeSelectorRequirement{
|
||||
{
|
||||
Key: "key2",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value2"},
|
||||
},
|
||||
{
|
||||
Key: "key3",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
MatchExpressions: []v1.NodeSelectorRequirement{
|
||||
{
|
||||
Key: "key1",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value11, test-value12"},
|
||||
},
|
||||
{
|
||||
Key: "key4",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value41, test-value42"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
exists: true,
|
||||
},
|
||||
{
|
||||
name: "key existence in terms with one of the keys specfied",
|
||||
reqs: []v1.NodeSelectorRequirement{
|
||||
{
|
||||
Key: "key1",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value1"},
|
||||
},
|
||||
{
|
||||
Key: "key2",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value2"},
|
||||
},
|
||||
{
|
||||
Key: "key3",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value3"},
|
||||
},
|
||||
{
|
||||
Key: "key6",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value6"},
|
||||
},
|
||||
},
|
||||
terms: []v1.NodeSelectorTerm{
|
||||
{
|
||||
MatchExpressions: []v1.NodeSelectorRequirement{
|
||||
{
|
||||
Key: "key2",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value2"},
|
||||
}, {
|
||||
Key: "key4",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value4"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
MatchExpressions: []v1.NodeSelectorRequirement{
|
||||
{
|
||||
Key: "key5",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value5"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
exists: true,
|
||||
},
|
||||
{
|
||||
name: "key existence in terms without any of the keys specified",
|
||||
reqs: []v1.NodeSelectorRequirement{
|
||||
{
|
||||
Key: "key2",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value2"},
|
||||
},
|
||||
{
|
||||
Key: "key3",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value3"},
|
||||
},
|
||||
},
|
||||
terms: []v1.NodeSelectorTerm{
|
||||
{
|
||||
MatchExpressions: []v1.NodeSelectorRequirement{
|
||||
{
|
||||
Key: "key4",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value"},
|
||||
},
|
||||
{
|
||||
Key: "key5",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
MatchExpressions: []v1.NodeSelectorRequirement{
|
||||
{
|
||||
Key: "key6",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
MatchExpressions: []v1.NodeSelectorRequirement{
|
||||
{
|
||||
Key: "key7",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value"},
|
||||
},
|
||||
{
|
||||
Key: "key8",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
exists: false,
|
||||
},
|
||||
{
|
||||
name: "key existence in empty set of terms",
|
||||
reqs: []v1.NodeSelectorRequirement{
|
||||
{
|
||||
Key: "key2",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value2"},
|
||||
},
|
||||
{
|
||||
Key: "key3",
|
||||
Operator: v1.NodeSelectorOpIn,
|
||||
Values: []string{"test-value3"},
|
||||
},
|
||||
},
|
||||
terms: []v1.NodeSelectorTerm{},
|
||||
exists: false,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
keyExists := NodeSelectorRequirementKeysExistInNodeSelectorTerms(test.reqs, test.terms)
|
||||
if test.exists != keyExists {
|
||||
t.Errorf("test %s failed. Expected %v but got %v", test.name, test.exists, keyExists)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user