Add DynamicProvisioningScheduling support for EBS

Signed-off-by: Deep Debroy <ddebroy@docker.com>
This commit is contained in:
Deep Debroy
2018-08-01 09:00:03 -07:00
parent 845a55dbbd
commit 217a3d8902
8 changed files with 646 additions and 82 deletions

View File

@@ -37,6 +37,8 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
"k8s.io/kubernetes/pkg/util/slice"
"k8s.io/kubernetes/pkg/volume"
@@ -1021,6 +1023,443 @@ func TestValidateZone(t *testing.T) {
}
}
func TestSelectZoneForVolume(t *testing.T) {
nodeWithZoneLabels := &v1.Node{}
nodeWithZoneLabels.Labels = map[string]string{kubeletapis.LabelZoneFailureDomain: "zoneX"}
nodeWithNoLabels := &v1.Node{}
tests := []struct {
// Parameters passed by test to SelectZoneForVolume
Name string
ZonePresent bool
Zone string
ZonesPresent bool
Zones string
ZonesWithNodes string
Node *v1.Node
AllowedTopologies []v1.TopologySelectorTerm
DynamicProvisioningScheduling bool
// Expectations around returned zone from SelectZoneForVolume
Reject bool // expect error due to validation failing
ExpectSpecificZone bool // expect returned zone to specifically match a single zone (rather than one from a set)
ExpectedZone string // single zone that should perfectly match returned zone (requires ExpectSpecificZone to be true)
ExpectedZones string // set of zones one of whose members should match returned zone (requires ExpectSpecificZone to be false)
}{
// NEGATIVE TESTS
// Zone and Zones are both specified [Fail]
// [1] Node irrelevant
// [2] Zone and Zones parameters presents
// [3] AllowedTopologies irrelevant
// [4] DynamicProvisioningScheduling irrelevant
{
Name: "Nil_Node_with_Zone_Zones_parameters_present",
ZonePresent: true,
Zone: "zoneX",
ZonesPresent: true,
Zones: "zoneX,zoneY",
Reject: true,
},
// Node has no zone labels [Fail]
// [1] Node with no zone labels
// [2] Zone/Zones parameter irrelevant
// [3] AllowedTopologies irrelevant
// [4] DynamicProvisioningScheduling enabled
{
Name: "Node_with_no_Zone_labels",
Node: nodeWithNoLabels,
DynamicProvisioningScheduling: true,
Reject: true,
},
// Node with Zone labels as well as Zone parameter specified [Fail]
// [1] Node with zone labels
// [2] Zone parameter specified
// [3] AllowedTopologies irrelevant
// [4] DynamicProvisioningScheduling enabled
{
Name: "Node_with_Zone_labels_and_Zone_parameter_present",
Node: nodeWithZoneLabels,
ZonePresent: true,
Zone: "zoneX",
DynamicProvisioningScheduling: true,
Reject: true,
},
// Node with Zone labels as well as Zones parameter specified [Fail]
// [1] Node with zone labels
// [2] Zones parameter specified
// [3] AllowedTopologies irrelevant
// [4] DynamicProvisioningScheduling enabled
{
Name: "Node_with_Zone_labels_and_Zones_parameter_present",
Node: nodeWithZoneLabels,
ZonesPresent: true,
Zones: "zoneX,zoneY",
DynamicProvisioningScheduling: true,
Reject: true,
},
// Zone parameter as well as AllowedTopologies specified [Fail]
// [1] nil Node
// [2] Zone parameter specified
// [3] AllowedTopologies specified
// [4] DynamicProvisioningScheduling enabled
{
Name: "Nil_Node_and_Zone_parameter_and_Allowed_Topology_term",
Node: nil,
ZonePresent: true,
Zone: "zoneX",
DynamicProvisioningScheduling: true,
AllowedTopologies: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: kubeletapis.LabelZoneFailureDomain,
Values: []string{"zoneX"},
},
},
},
},
Reject: true,
},
// Zones parameter as well as AllowedTopologies specified [Fail]
// [1] nil Node
// [2] Zones parameter specified
// [3] AllowedTopologies specified
// [4] DynamicProvisioningScheduling enabled
{
Name: "Nil_Node_and_Zones_parameter_and_Allowed_Topology_term",
Node: nil,
ZonesPresent: true,
Zones: "zoneX,zoneY",
DynamicProvisioningScheduling: true,
AllowedTopologies: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: kubeletapis.LabelZoneFailureDomain,
Values: []string{"zoneX"},
},
},
},
},
Reject: true,
},
// Key specified in AllowedTopologies is not LabelZoneFailureDomain [Fail]
// [1] nil Node
// [2] no Zone/Zones parameter
// [3] AllowedTopologies with invalid key specified
// [4] DynamicProvisioningScheduling enabled
{
Name: "Nil_Node_and_Invalid_Allowed_Topology_Key",
Node: nil,
DynamicProvisioningScheduling: true,
AllowedTopologies: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: "invalid_key",
Values: []string{"zoneX"},
},
{
Key: kubeletapis.LabelZoneFailureDomain,
Values: []string{"zoneY"},
},
},
},
},
Reject: true,
},
// AllowedTopologies without keys specifying LabelZoneFailureDomain [Fail]
// [1] nil Node
// [2] no Zone/Zones parameter
// [3] Invalid AllowedTopologies
// [4] DynamicProvisioningScheduling enabled
{
Name: "Nil_Node_and_Invalid_AllowedTopologies",
Node: nil,
DynamicProvisioningScheduling: true,
AllowedTopologies: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{},
},
},
Reject: true,
},
// POSITIVE TESTS WITH DynamicProvisioningScheduling DISABLED
// Select zone from active zones [Pass]
// [1] nil Node (Node irrelevant)
// [2] no Zone parameter
// [3] no AllowedTopologies
// [4] DynamicProvisioningScheduling disabled
{
Name: "No_Zone_Zones_parameter_and_DynamicProvisioningScheduling_disabled",
ZonesWithNodes: "zoneX,zoneY",
DynamicProvisioningScheduling: false,
Reject: false,
ExpectedZones: "zoneX,zoneY",
},
// Select zone from single zone parameter [Pass]
// [1] nil Node (Node irrelevant)
// [2] Zone parameter specified
// [3] no AllowedTopologies
// [4] DynamicProvisioningScheduling disabled
{
Name: "Zone_parameter_present_and_DynamicProvisioningScheduling_disabled",
ZonePresent: true,
Zone: "zoneX",
DynamicProvisioningScheduling: false,
Reject: false,
ExpectSpecificZone: true,
ExpectedZone: "zoneX",
},
// Select zone from zones parameter [Pass]
// [1] nil Node (Node irrelevant)
// [2] Zones parameter specified
// [3] no AllowedTopologies
// [4] DynamicProvisioningScheduling disabled
{
Name: "Zones_parameter_present_and_DynamicProvisioningScheduling_disabled",
ZonesPresent: true,
Zones: "zoneX,zoneY",
DynamicProvisioningScheduling: false,
Reject: false,
ExpectedZones: "zoneX,zoneY",
},
// POSITIVE TESTS WITH DynamicProvisioningScheduling ENABLED
// Select zone from active zones [Pass]
// [1] nil Node
// [2] no Zone parameter specified
// [3] no AllowedTopologies
// [4] DynamicProvisioningScheduling enabled
{
Name: "Nil_Node_and_No_Zone_Zones_parameter_and_no_Allowed_topologies_and_DynamicProvisioningScheduling_enabled",
Node: nil,
ZonesWithNodes: "zoneX,zoneY",
DynamicProvisioningScheduling: true,
Reject: false,
ExpectedZones: "zoneX,zoneY",
},
// Select zone from single zone parameter [Pass]
// [1] nil Node
// [2] Zone parameter specified
// [3] no AllowedTopology specified
// [4] DynamicSchedulingEnabled enabled
{
Name: "Nil_Node_and_Zone_parameter_present_and_DynamicProvisioningScheduling_enabled",
ZonePresent: true,
Zone: "zoneX",
Node: nil,
DynamicProvisioningScheduling: true,
Reject: false,
ExpectSpecificZone: true,
ExpectedZone: "zoneX",
},
// Select zone from zones parameter [Pass]
// [1] nil Node
// [2] Zones parameter specified
// [3] no AllowedTopology
// [4] DynamicSchedulingEnabled enabled
{
Name: "Nil_Node_and_Zones_parameter_present_and_DynamicProvisioningScheduling_enabled",
ZonesPresent: true,
Zones: "zoneX,zoneY",
Node: nil,
DynamicProvisioningScheduling: true,
Reject: false,
ExpectedZones: "zoneX,zoneY",
},
// Select zone from node label [Pass]
// [1] Node with zone labels
// [2] no zone/zones parameters
// [3] no AllowedTopology
// [4] DynamicProvisioningScheduling enabled
{
Name: "Node_with_Zone_labels_and_DynamicProvisioningScheduling_enabled",
Node: nodeWithZoneLabels,
DynamicProvisioningScheduling: true,
Reject: false,
ExpectSpecificZone: true,
ExpectedZone: "zoneX",
},
// Select zone from node label [Pass]
// [1] Node with zone labels
// [2] no Zone/Zones parameters
// [3] AllowedTopology with single term with multiple values specified (ignored)
// [4] DynamicProvisioningScheduling enabled
{
Name: "Node_with_Zone_labels_and_Multiple_Allowed_Topology_values_and_DynamicProvisioningScheduling_enabled",
Node: nodeWithZoneLabels,
DynamicProvisioningScheduling: true,
AllowedTopologies: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: kubeletapis.LabelZoneFailureDomain,
Values: []string{"zoneZ", "zoneY"},
},
},
},
},
Reject: false,
ExpectSpecificZone: true,
ExpectedZone: "zoneX",
},
// Select Zone from AllowedTopologies [Pass]
// [1] nil Node
// [2] no Zone/Zones parametes specified
// [3] AllowedTopologies with single term with multiple values specified
// [4] DynamicProvisioningScheduling enabled
{
Name: "Nil_Node_with_Multiple_Allowed_Topology_values_and_DynamicProvisioningScheduling_enabled",
Node: nil,
DynamicProvisioningScheduling: true,
AllowedTopologies: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: kubeletapis.LabelZoneFailureDomain,
Values: []string{"zoneX", "zoneY"},
},
},
},
},
Reject: false,
ExpectedZones: "zoneX,zoneY",
},
// Select zone from AllowedTopologies [Pass]
// [1] nil Node
// [2] no Zone/Zones parametes specified
// [3] AllowedTopologies with multiple terms specified
// [4] DynamicProvisioningScheduling enabled
{
Name: "Nil_Node_and_Multiple_Allowed_Topology_terms_and_DynamicProvisioningScheduling_enabled",
Node: nil,
DynamicProvisioningScheduling: true,
AllowedTopologies: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: kubeletapis.LabelZoneFailureDomain,
Values: []string{"zoneX"},
},
},
},
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: kubeletapis.LabelZoneFailureDomain,
Values: []string{"zoneY"},
},
},
},
},
Reject: false,
ExpectedZones: "zoneX,zoneY",
},
// Select Zone from AllowedTopologies [Pass]
// Note: Dual replica with same AllowedTopologies will fail: Nil_Node_and_Single_Allowed_Topology_term_value_and_Dual_replicas
// [1] nil Node
// [2] no Zone/Zones parametes specified
// [3] AllowedTopologies with single term and value specified
// [4] DynamicProvisioningScheduling enabled
{
Name: "Nil_Node_and_Single_Allowed_Topology_term_value_and_DynamicProvisioningScheduling_enabled",
Node: nil,
DynamicProvisioningScheduling: true,
AllowedTopologies: []v1.TopologySelectorTerm{
{
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
{
Key: kubeletapis.LabelZoneFailureDomain,
Values: []string{"zoneX"},
},
},
},
},
Reject: false,
ExpectSpecificZone: true,
ExpectedZone: "zoneX",
},
}
for _, test := range tests {
utilfeature.DefaultFeatureGate.Set("DynamicProvisioningScheduling=false")
if test.DynamicProvisioningScheduling {
utilfeature.DefaultFeatureGate.Set("DynamicProvisioningScheduling=true")
}
var zonesParameter, zonesWithNodes sets.String
var err error
if test.Zones != "" {
zonesParameter, err = ZonesToSet(test.Zones)
if err != nil {
t.Errorf("Could not convert Zones to a set: %s. This is a test error %s", test.Zones, test.Name)
continue
}
}
if test.ZonesWithNodes != "" {
zonesWithNodes, err = ZonesToSet(test.ZonesWithNodes)
if err != nil {
t.Errorf("Could not convert specified ZonesWithNodes to a set: %s. This is a test error %s", test.ZonesWithNodes, test.Name)
continue
}
}
zone, err := SelectZoneForVolume(test.ZonePresent, test.ZonesPresent, test.Zone, zonesParameter, zonesWithNodes, test.Node, test.AllowedTopologies, test.Name)
if test.Reject && err == nil {
t.Errorf("Unexpected zone from SelectZoneForVolume for %s", zone)
continue
}
if !test.Reject {
if err != nil {
t.Errorf("Unexpected error from SelectZoneForVolume for %s; Error: %v", test.Name, err)
continue
}
if test.ExpectSpecificZone == true {
if zone != test.ExpectedZone {
t.Errorf("Expected zone %v does not match obtained zone %v for %s", test.ExpectedZone, zone, test.Name)
}
continue
}
expectedZones, err := ZonesToSet(test.ExpectedZones)
if err != nil {
t.Errorf("Could not convert ExpectedZones to a set: %s. This is a test error", test.ExpectedZones)
continue
}
if !expectedZones.Has(zone) {
t.Errorf("Obtained zone %s not member of expectedZones %s", zone, expectedZones)
}
}
}
}
func TestGetWindowsPath(t *testing.T) {
tests := []struct {
path string