Merge pull request #65424 from liggitt/scheduler-config

Automatic merge from submit-queue. 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>.

Fix scheduler config decoding

Fixes #65413

Implements a custom unmarshaler for a single scheduler config type which did not correctly specify JSON tags until https://github.com/kubernetes/kubernetes/issues/65414 is resolved

Adds missing compatibility tests for scheduler extenders back to 1.7

```release-note
Fixes incompatibility with custom scheduler extender configurations specifying `bindVerb`
```
pull/8/head
Kubernetes Submit Queue 2018-06-25 00:21:35 -07:00 committed by GitHub
commit a13fe4d15d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 132 additions and 5 deletions

View File

@ -349,7 +349,17 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
{"name": "TaintTolerationPriority", "weight": 2}, {"name": "TaintTolerationPriority", "weight": 2},
{"name": "InterPodAffinityPriority", "weight": 2}, {"name": "InterPodAffinityPriority", "weight": 2},
{"name": "MostRequestedPriority", "weight": 2} {"name": "MostRequestedPriority", "weight": 2}
] ],"extenders": [{
"urlPrefix": "/prefix",
"filterVerb": "filter",
"prioritizeVerb": "prioritize",
"weight": 1,
"BindVerb": "bind",
"enableHttps": true,
"tlsConfig": {"Insecure":true},
"httpTimeout": 1,
"nodeCacheCapable": true
}]
}`, }`,
ExpectedPolicy: schedulerapi.Policy{ ExpectedPolicy: schedulerapi.Policy{
Predicates: []schedulerapi.PredicatePolicy{ Predicates: []schedulerapi.PredicatePolicy{
@ -382,6 +392,17 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
{Name: "InterPodAffinityPriority", Weight: 2}, {Name: "InterPodAffinityPriority", Weight: 2},
{Name: "MostRequestedPriority", Weight: 2}, {Name: "MostRequestedPriority", Weight: 2},
}, },
ExtenderConfigs: []schedulerapi.ExtenderConfig{{
URLPrefix: "/prefix",
FilterVerb: "filter",
PrioritizeVerb: "prioritize",
Weight: 1,
BindVerb: "bind", // 1.7 was missing json tags on the BindVerb field and required "BindVerb"
EnableHTTPS: true,
TLSConfig: &restclient.TLSClientConfig{Insecure: true},
HTTPTimeout: 1,
NodeCacheCapable: true,
}},
}, },
}, },
// Do not change this JSON after the corresponding release has been tagged. // Do not change this JSON after the corresponding release has been tagged.
@ -419,7 +440,17 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
{"name": "TaintTolerationPriority", "weight": 2}, {"name": "TaintTolerationPriority", "weight": 2},
{"name": "InterPodAffinityPriority", "weight": 2}, {"name": "InterPodAffinityPriority", "weight": 2},
{"name": "MostRequestedPriority", "weight": 2} {"name": "MostRequestedPriority", "weight": 2}
] ],"extenders": [{
"urlPrefix": "/prefix",
"filterVerb": "filter",
"prioritizeVerb": "prioritize",
"weight": 1,
"bindVerb": "bind",
"enableHttps": true,
"tlsConfig": {"Insecure":true},
"httpTimeout": 1,
"nodeCacheCapable": true
}]
}`, }`,
ExpectedPolicy: schedulerapi.Policy{ ExpectedPolicy: schedulerapi.Policy{
Predicates: []schedulerapi.PredicatePolicy{ Predicates: []schedulerapi.PredicatePolicy{
@ -453,6 +484,17 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
{Name: "InterPodAffinityPriority", Weight: 2}, {Name: "InterPodAffinityPriority", Weight: 2},
{Name: "MostRequestedPriority", Weight: 2}, {Name: "MostRequestedPriority", Weight: 2},
}, },
ExtenderConfigs: []schedulerapi.ExtenderConfig{{
URLPrefix: "/prefix",
FilterVerb: "filter",
PrioritizeVerb: "prioritize",
Weight: 1,
BindVerb: "bind", // 1.8 became case-insensitive and tolerated "bindVerb"
EnableHTTPS: true,
TLSConfig: &restclient.TLSClientConfig{Insecure: true},
HTTPTimeout: 1,
NodeCacheCapable: true,
}},
}, },
}, },
// Do not change this JSON after the corresponding release has been tagged. // Do not change this JSON after the corresponding release has been tagged.
@ -491,7 +533,17 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
{"name": "TaintTolerationPriority", "weight": 2}, {"name": "TaintTolerationPriority", "weight": 2},
{"name": "InterPodAffinityPriority", "weight": 2}, {"name": "InterPodAffinityPriority", "weight": 2},
{"name": "MostRequestedPriority", "weight": 2} {"name": "MostRequestedPriority", "weight": 2}
] ],"extenders": [{
"urlPrefix": "/prefix",
"filterVerb": "filter",
"prioritizeVerb": "prioritize",
"weight": 1,
"bindVerb": "bind",
"enableHttps": true,
"tlsConfig": {"Insecure":true},
"httpTimeout": 1,
"nodeCacheCapable": true
}]
}`, }`,
ExpectedPolicy: schedulerapi.Policy{ ExpectedPolicy: schedulerapi.Policy{
Predicates: []schedulerapi.PredicatePolicy{ Predicates: []schedulerapi.PredicatePolicy{
@ -526,8 +578,20 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
{Name: "InterPodAffinityPriority", Weight: 2}, {Name: "InterPodAffinityPriority", Weight: 2},
{Name: "MostRequestedPriority", Weight: 2}, {Name: "MostRequestedPriority", Weight: 2},
}, },
ExtenderConfigs: []schedulerapi.ExtenderConfig{{
URLPrefix: "/prefix",
FilterVerb: "filter",
PrioritizeVerb: "prioritize",
Weight: 1,
BindVerb: "bind", // 1.9 was case-insensitive and tolerated "bindVerb"
EnableHTTPS: true,
TLSConfig: &restclient.TLSClientConfig{Insecure: true},
HTTPTimeout: 1,
NodeCacheCapable: true,
}},
}, },
}, },
// Do not change this JSON after the corresponding release has been tagged. // Do not change this JSON after the corresponding release has been tagged.
// A failure indicates backwards compatibility with the specified release was broken. // A failure indicates backwards compatibility with the specified release was broken.
"1.10": { "1.10": {
@ -565,7 +629,19 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
{"name": "TaintTolerationPriority", "weight": 2}, {"name": "TaintTolerationPriority", "weight": 2},
{"name": "InterPodAffinityPriority", "weight": 2}, {"name": "InterPodAffinityPriority", "weight": 2},
{"name": "MostRequestedPriority", "weight": 2} {"name": "MostRequestedPriority", "weight": 2}
] ],"extenders": [{
"urlPrefix": "/prefix",
"filterVerb": "filter",
"prioritizeVerb": "prioritize",
"weight": 1,
"bindVerb": "bind",
"enableHttps": true,
"tlsConfig": {"Insecure":true},
"httpTimeout": 1,
"nodeCacheCapable": true,
"managedResources": [{"name":"example.com/foo","ignoredByScheduler":true}],
"ignorable":true
}]
}`, }`,
ExpectedPolicy: schedulerapi.Policy{ ExpectedPolicy: schedulerapi.Policy{
Predicates: []schedulerapi.PredicatePolicy{ Predicates: []schedulerapi.PredicatePolicy{
@ -601,6 +677,19 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
{Name: "InterPodAffinityPriority", Weight: 2}, {Name: "InterPodAffinityPriority", Weight: 2},
{Name: "MostRequestedPriority", Weight: 2}, {Name: "MostRequestedPriority", Weight: 2},
}, },
ExtenderConfigs: []schedulerapi.ExtenderConfig{{
URLPrefix: "/prefix",
FilterVerb: "filter",
PrioritizeVerb: "prioritize",
Weight: 1,
BindVerb: "bind", // 1.10 was case-insensitive and tolerated "bindVerb"
EnableHTTPS: true,
TLSConfig: &restclient.TLSClientConfig{Insecure: true},
HTTPTimeout: 1,
NodeCacheCapable: true,
ManagedResources: []schedulerapi.ExtenderManagedResource{{Name: v1.ResourceName("example.com/foo"), IgnoredByScheduler: true}},
Ignorable: true,
}},
}, },
}, },
// Do not change this JSON after the corresponding release has been tagged. // Do not change this JSON after the corresponding release has been tagged.
@ -651,7 +740,19 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
] ]
} }
}} }}
] ],"extenders": [{
"urlPrefix": "/prefix",
"filterVerb": "filter",
"prioritizeVerb": "prioritize",
"weight": 1,
"bindVerb": "bind",
"enableHttps": true,
"tlsConfig": {"Insecure":true},
"httpTimeout": 1,
"nodeCacheCapable": true,
"managedResources": [{"name":"example.com/foo","ignoredByScheduler":true}],
"ignorable":true
}]
}`, }`,
ExpectedPolicy: schedulerapi.Policy{ ExpectedPolicy: schedulerapi.Policy{
Predicates: []schedulerapi.PredicatePolicy{ Predicates: []schedulerapi.PredicatePolicy{
@ -698,6 +799,19 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
}, },
}, },
}, },
ExtenderConfigs: []schedulerapi.ExtenderConfig{{
URLPrefix: "/prefix",
FilterVerb: "filter",
PrioritizeVerb: "prioritize",
Weight: 1,
BindVerb: "bind", // 1.11 restored case-sensitivity, but allowed either "BindVerb" or "bindVerb"
EnableHTTPS: true,
TLSConfig: &restclient.TLSClientConfig{Insecure: true},
HTTPTimeout: 1,
NodeCacheCapable: true,
ManagedResources: []schedulerapi.ExtenderManagedResource{{Name: v1.ResourceName("example.com/foo"), IgnoredByScheduler: true}},
Ignorable: true,
}},
}, },
}, },
} }

View File

@ -17,6 +17,7 @@ limitations under the License.
package v1 package v1
import ( import (
gojson "encoding/json"
"time" "time"
apiv1 "k8s.io/api/core/v1" apiv1 "k8s.io/api/core/v1"
@ -195,6 +196,18 @@ type ExtenderConfig struct {
Ignorable bool `json:"ignorable,omitempty"` Ignorable bool `json:"ignorable,omitempty"`
} }
// caseInsensitiveExtenderConfig is a type alias which lets us use the stdlib case-insensitive decoding
// to preserve compatibility with incorrectly specified scheduler config fields:
// * BindVerb, which originally did not specify a json tag, and required upper-case serialization in 1.7
// * TLSConfig, which uses a struct not intended for serialization, and does not include any json tags
type caseInsensitiveExtenderConfig *ExtenderConfig
// UnmarshalJSON implements the json.Unmarshaller interface.
// This preserves compatibility with incorrect case-insensitive configuration fields.
func (t *ExtenderConfig) UnmarshalJSON(b []byte) error {
return gojson.Unmarshal(b, caseInsensitiveExtenderConfig(t))
}
// ExtenderArgs represents the arguments needed by the extender to filter/prioritize // ExtenderArgs represents the arguments needed by the extender to filter/prioritize
// nodes for a pod. // nodes for a pod.
type ExtenderArgs struct { type ExtenderArgs struct {