diff --git a/staging/publishing/import-restrictions.yaml b/staging/publishing/import-restrictions.yaml index ac4776f367c..4422f5f06bb 100644 --- a/staging/publishing/import-restrictions.yaml +++ b/staging/publishing/import-restrictions.yaml @@ -194,6 +194,7 @@ - baseImportPath: "./vendor/k8s.io/kube-scheduler/" allowedImports: + - k8s.io/api - k8s.io/apimachinery - k8s.io/component-base - k8s.io/klog diff --git a/staging/src/k8s.io/kube-scheduler/extender/OWNERS b/staging/src/k8s.io/kube-scheduler/extender/OWNERS new file mode 100644 index 00000000000..7fbfadd4f4a --- /dev/null +++ b/staging/src/k8s.io/kube-scheduler/extender/OWNERS @@ -0,0 +1,13 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +# Disable inheritance as this is an api owners file +options: + no_parent_owners: true +approvers: +- api-approvers +reviewers: +- api-reviewers +- sig-scheduling +labels: +- kind/api-change +- sig/scheduling diff --git a/staging/src/k8s.io/kube-scheduler/extender/v1/BUILD b/staging/src/k8s.io/kube-scheduler/extender/v1/BUILD index df3ab5a0d51..dd3ce8195cd 100644 --- a/staging/src/k8s.io/kube-scheduler/extender/v1/BUILD +++ b/staging/src/k8s.io/kube-scheduler/extender/v1/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", @@ -29,3 +29,15 @@ filegroup( tags = ["automanaged"], visibility = ["//visibility:public"], ) + +go_test( + name = "go_default_test", + srcs = ["types_test.go"], + embed = [":go_default_library"], + deps = [ + "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", + "//vendor/github.com/google/go-cmp/cmp:go_default_library", + ], +) diff --git a/staging/src/k8s.io/kube-scheduler/extender/v1/types_test.go b/staging/src/k8s.io/kube-scheduler/extender/v1/types_test.go new file mode 100644 index 00000000000..201a1b54d96 --- /dev/null +++ b/staging/src/k8s.io/kube-scheduler/extender/v1/types_test.go @@ -0,0 +1,116 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "encoding/json" + "reflect" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// TestCompatibility verifies that the types in extender/v1 can be successfully encoded to json and decoded back, even when lowercased, +// since these types were written around JSON tags and we need to enforce consistency on them now. +// @TODO(88634): v2 of these types should be defined with proper JSON tags to enforce field casing to a single approach +func TestCompatibility(t *testing.T) { + testcases := []struct { + emptyObj interface{} + obj interface{} + expectJSON string + }{ + { + emptyObj: &ExtenderPreemptionResult{}, + obj: &ExtenderPreemptionResult{ + NodeNameToMetaVictims: map[string]*MetaVictims{"foo": {Pods: []*MetaPod{{UID: "myuid"}}, NumPDBViolations: 1}}, + }, + expectJSON: `{"NodeNameToMetaVictims":{"foo":{"Pods":[{"UID":"myuid"}],"NumPDBViolations":1}}}`, + }, + { + emptyObj: &ExtenderPreemptionArgs{}, + obj: &ExtenderPreemptionArgs{ + Pod: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "podname"}}, + NodeNameToVictims: map[string]*Victims{"foo": {Pods: []*v1.Pod{&corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "podname"}}}, NumPDBViolations: 1}}, + NodeNameToMetaVictims: map[string]*MetaVictims{"foo": {Pods: []*MetaPod{{UID: "myuid"}}, NumPDBViolations: 1}}, + }, + expectJSON: `{"Pod":{"metadata":{"name":"podname","creationTimestamp":null},"spec":{"containers":null},"status":{}},"NodeNameToVictims":{"foo":{"Pods":[{"metadata":{"name":"podname","creationTimestamp":null},"spec":{"containers":null},"status":{}}],"NumPDBViolations":1}},"NodeNameToMetaVictims":{"foo":{"Pods":[{"UID":"myuid"}],"NumPDBViolations":1}}}`, + }, + { + emptyObj: &ExtenderArgs{}, + obj: &ExtenderArgs{ + Pod: &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "podname"}}, + Nodes: &corev1.NodeList{Items: []corev1.Node{{ObjectMeta: metav1.ObjectMeta{Name: "nodename"}}}}, + NodeNames: &[]string{"node1"}, + }, + expectJSON: `{"Pod":{"metadata":{"name":"podname","creationTimestamp":null},"spec":{"containers":null},"status":{}},"Nodes":{"metadata":{},"items":[{"metadata":{"name":"nodename","creationTimestamp":null},"spec":{},"status":{"daemonEndpoints":{"kubeletEndpoint":{"Port":0}},"nodeInfo":{"machineID":"","systemUUID":"","bootID":"","kernelVersion":"","osImage":"","containerRuntimeVersion":"","kubeletVersion":"","kubeProxyVersion":"","operatingSystem":"","architecture":""}}}]},"NodeNames":["node1"]}`, + }, + { + emptyObj: &ExtenderFilterResult{}, + obj: &ExtenderFilterResult{ + Nodes: &corev1.NodeList{Items: []corev1.Node{{ObjectMeta: metav1.ObjectMeta{Name: "nodename"}}}}, + NodeNames: &[]string{"node1"}, + FailedNodes: FailedNodesMap{"foo": "bar"}, + Error: "myerror", + }, + expectJSON: `{"Nodes":{"metadata":{},"items":[{"metadata":{"name":"nodename","creationTimestamp":null},"spec":{},"status":{"daemonEndpoints":{"kubeletEndpoint":{"Port":0}},"nodeInfo":{"machineID":"","systemUUID":"","bootID":"","kernelVersion":"","osImage":"","containerRuntimeVersion":"","kubeletVersion":"","kubeProxyVersion":"","operatingSystem":"","architecture":""}}}]},"NodeNames":["node1"],"FailedNodes":{"foo":"bar"},"Error":"myerror"}`, + }, + { + emptyObj: &ExtenderBindingArgs{}, + obj: &ExtenderBindingArgs{ + PodName: "mypodname", + PodNamespace: "mypodnamespace", + PodUID: types.UID("mypoduid"), + Node: "mynode", + }, + expectJSON: `{"PodName":"mypodname","PodNamespace":"mypodnamespace","PodUID":"mypoduid","Node":"mynode"}`, + }, + { + emptyObj: &ExtenderBindingResult{}, + obj: &ExtenderBindingResult{Error: "myerror"}, + expectJSON: `{"Error":"myerror"}`, + }, + { + emptyObj: &HostPriority{}, + obj: &HostPriority{Host: "myhost", Score: 1}, + expectJSON: `{"Host":"myhost","Score":1}`, + }, + } + + for _, tc := range testcases { + t.Run(reflect.TypeOf(tc.obj).String(), func(t *testing.T) { + data, err := json.Marshal(tc.obj) + if err != nil { + t.Fatal(err) + } + if string(data) != tc.expectJSON { + t.Fatalf("expected %s, got %s", tc.expectJSON, string(data)) + } + if err := json.Unmarshal([]byte(strings.ToLower(string(data))), tc.emptyObj); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(tc.emptyObj, tc.obj) { + t.Fatalf("round-tripped case-insensitive diff: %s", cmp.Diff(tc.obj, tc.emptyObj)) + } + }) + } +} diff --git a/staging/src/k8s.io/kube-scheduler/go.mod b/staging/src/k8s.io/kube-scheduler/go.mod index 0c92b6f348c..9dcfaeee8c8 100644 --- a/staging/src/k8s.io/kube-scheduler/go.mod +++ b/staging/src/k8s.io/kube-scheduler/go.mod @@ -5,6 +5,8 @@ module k8s.io/kube-scheduler go 1.13 require ( + github.com/google/go-cmp v0.3.0 + k8s.io/api v0.0.0 k8s.io/apimachinery v0.0.0 k8s.io/component-base v0.0.0 ) diff --git a/vendor/modules.txt b/vendor/modules.txt index 3ae95871ab2..1fb00b6c4c3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1777,6 +1777,7 @@ k8s.io/kube-proxy/config/v1alpha1 k8s.io/kube-scheduler/config/v1 k8s.io/kube-scheduler/config/v1alpha1 k8s.io/kube-scheduler/config/v1alpha2 +k8s.io/kube-scheduler/extender/v1 # k8s.io/kubectl v0.0.0 => ./staging/src/k8s.io/kubectl k8s.io/kubectl/pkg/apps k8s.io/kubectl/pkg/cmd