mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #4964 from lavalamp/fix6
Put #4575 back in and fix e2e failure
This commit is contained in:
commit
fe1edcfeda
@ -1291,4 +1291,26 @@ func init() {
|
||||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Add field conversion funcs.
|
||||
err = newer.Scheme.AddFieldLabelConversionFunc("v1beta1", "pods",
|
||||
func(label, value string) (string, string, error) {
|
||||
switch label {
|
||||
case "name":
|
||||
return "name", value, nil
|
||||
case "DesiredState.Host":
|
||||
return "Status.Host", value, nil
|
||||
case "DesiredState.Status":
|
||||
podStatus := PodStatus(value)
|
||||
var internalValue newer.PodPhase
|
||||
newer.Scheme.Convert(&podStatus, &internalValue)
|
||||
return "Status.Phase", string(internalValue), nil
|
||||
default:
|
||||
return "", "", fmt.Errorf("field label not supported: %s", label)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
@ -1206,4 +1206,26 @@ func init() {
|
||||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Add field conversion funcs.
|
||||
err = newer.Scheme.AddFieldLabelConversionFunc("v1beta2", "pods",
|
||||
func(label, value string) (string, string, error) {
|
||||
switch label {
|
||||
case "name":
|
||||
return "name", value, nil
|
||||
case "DesiredState.Host":
|
||||
return "Status.Host", value, nil
|
||||
case "DesiredState.Status":
|
||||
podStatus := PodStatus(value)
|
||||
var internalValue newer.PodPhase
|
||||
newer.Scheme.Convert(&podStatus, &internalValue)
|
||||
return "Status.Phase", string(internalValue), nil
|
||||
default:
|
||||
return "", "", fmt.Errorf("field label not supported: %s", label)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
44
pkg/api/v1beta3/conversion.go
Normal file
44
pkg/api/v1beta3/conversion.go
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
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 v1beta3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
newer "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Add field conversion funcs.
|
||||
err := newer.Scheme.AddFieldLabelConversionFunc("v1beta3", "pods",
|
||||
func(label, value string) (string, string, error) {
|
||||
switch label {
|
||||
case "name":
|
||||
fallthrough
|
||||
case "Status.Phase":
|
||||
fallthrough
|
||||
case "Status.Host":
|
||||
return label, value, nil
|
||||
default:
|
||||
return "", "", fmt.Errorf("field label not supported: %s", label)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
}
|
@ -242,7 +242,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage RESTStorage
|
||||
addParams(route, action.Params)
|
||||
ws.Route(route)
|
||||
case "LIST": // List all resources of a kind.
|
||||
route := ws.GET(action.Path).To(ListResource(lister, ctxFn, action.Namer, codec)).
|
||||
route := ws.GET(action.Path).To(ListResource(lister, ctxFn, action.Namer, codec, a.group.info)).
|
||||
Filter(m).
|
||||
Doc("list objects of kind " + kind).
|
||||
Operation("list" + kind).
|
||||
|
@ -18,6 +18,7 @@ package apiserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
gpath "path"
|
||||
"time"
|
||||
|
||||
@ -79,8 +80,24 @@ func GetResource(r RESTGetter, ctxFn ContextFunc, namer ScopeNamer, codec runtim
|
||||
}
|
||||
}
|
||||
|
||||
func parseSelectorQueryParams(query url.Values, version, apiResource string) (label, field labels.Selector, err error) {
|
||||
label, err = labels.ParseSelector(query.Get("labels"))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
convertToInternalVersionFunc := func(label, value string) (newLabel, newValue string, err error) {
|
||||
return api.Scheme.ConvertFieldLabel(version, apiResource, label, value)
|
||||
}
|
||||
field, err = labels.ParseAndTransformSelector(query.Get("fields"), convertToInternalVersionFunc)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return label, field, nil
|
||||
}
|
||||
|
||||
// ListResource returns a function that handles retrieving a list of resources from a RESTStorage object.
|
||||
func ListResource(r RESTLister, ctxFn ContextFunc, namer ScopeNamer, codec runtime.Codec) restful.RouteFunction {
|
||||
func ListResource(r RESTLister, ctxFn ContextFunc, namer ScopeNamer, codec runtime.Codec, requestInfoResolver *APIRequestInfoResolver) restful.RouteFunction {
|
||||
return func(req *restful.Request, res *restful.Response) {
|
||||
w := res.ResponseWriter
|
||||
|
||||
@ -92,12 +109,13 @@ func ListResource(r RESTLister, ctxFn ContextFunc, namer ScopeNamer, codec runti
|
||||
ctx := ctxFn(req)
|
||||
ctx = api.WithNamespace(ctx, namespace)
|
||||
|
||||
label, err := labels.ParseSelector(req.Request.URL.Query().Get("labels"))
|
||||
requestInfo, err := requestInfoResolver.GetAPIRequestInfo(req.Request)
|
||||
if err != nil {
|
||||
errorJSON(err, codec, w)
|
||||
return
|
||||
}
|
||||
field, err := labels.ParseSelector(req.Request.URL.Query().Get("fields"))
|
||||
|
||||
label, field, err := parseSelectorQueryParams(req.Request.URL.Query(), requestInfo.APIVersion, requestInfo.Resource)
|
||||
if err != nil {
|
||||
errorJSON(err, codec, w)
|
||||
return
|
||||
|
@ -18,7 +18,6 @@ package apiserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
@ -27,7 +26,6 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/httplog"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
watchjson "github.com/GoogleCloudPlatform/kubernetes/pkg/watch/json"
|
||||
@ -56,25 +54,6 @@ func (h *WatchHandler) setSelfLinkAddName(obj runtime.Object, req *http.Request)
|
||||
return h.linker.SetSelfLink(obj, newURL.String())
|
||||
}
|
||||
|
||||
func getWatchParams(query url.Values) (label, field labels.Selector, resourceVersion string, err error) {
|
||||
s, perr := labels.ParseSelector(query.Get("labels"))
|
||||
if perr != nil {
|
||||
err = perr
|
||||
return
|
||||
}
|
||||
label = s
|
||||
|
||||
s, perr = labels.ParseSelector(query.Get("fields"))
|
||||
if perr != nil {
|
||||
err = perr
|
||||
return
|
||||
}
|
||||
field = s
|
||||
|
||||
resourceVersion = query.Get("resourceVersion")
|
||||
return
|
||||
}
|
||||
|
||||
var connectionUpgradeRegex = regexp.MustCompile("(^|.*,\\s*)upgrade($|\\s*,)")
|
||||
|
||||
func isWebsocketRequest(req *http.Request) bool {
|
||||
@ -117,11 +96,13 @@ func (h *WatchHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
label, field, resourceVersion, err := getWatchParams(req.URL.Query())
|
||||
label, field, err := parseSelectorQueryParams(req.URL.Query(), requestInfo.APIVersion, apiResource)
|
||||
if err != nil {
|
||||
httpCode = errorJSON(err, h.codec, w)
|
||||
return
|
||||
}
|
||||
|
||||
resourceVersion := req.URL.Query().Get("resourceVersion")
|
||||
watching, err := watcher.Watch(ctx, label, field, resourceVersion)
|
||||
if err != nil {
|
||||
httpCode = errorJSON(err, h.codec, w)
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
"golang.org/x/net/websocket"
|
||||
@ -164,15 +165,19 @@ func TestWatchHTTP(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWatchParamParsing(t *testing.T) {
|
||||
api.Scheme.AddFieldLabelConversionFunc(testVersion, "foo",
|
||||
func(label, value string) (string, string, error) {
|
||||
return label, value, nil
|
||||
})
|
||||
simpleStorage := &SimpleRESTStorage{}
|
||||
handler := Handle(map[string]RESTStorage{
|
||||
"foo": simpleStorage,
|
||||
}, codec, "/api", "version", selfLinker, admissionControl, requestContextMapper, mapper)
|
||||
}, codec, "/api", testVersion, selfLinker, admissionControl, requestContextMapper, mapper)
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
|
||||
dest, _ := url.Parse(server.URL)
|
||||
dest.Path = "/api/version/watch/foo"
|
||||
dest.Path = "/api/" + testVersion + "/watch/foo"
|
||||
|
||||
table := []struct {
|
||||
rawQuery string
|
||||
@ -194,10 +199,10 @@ func TestWatchParamParsing(t *testing.T) {
|
||||
fieldSelector: "Host=",
|
||||
namespace: api.NamespaceDefault,
|
||||
}, {
|
||||
rawQuery: "namespace=watchother&fields=ID%3dfoo&resourceVersion=1492",
|
||||
rawQuery: "namespace=watchother&fields=id%3dfoo&resourceVersion=1492",
|
||||
resourceVersion: "1492",
|
||||
labelSelector: "",
|
||||
fieldSelector: "ID=foo",
|
||||
fieldSelector: "id=foo",
|
||||
namespace: "watchother",
|
||||
}, {
|
||||
rawQuery: "",
|
||||
@ -209,8 +214,8 @@ func TestWatchParamParsing(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, item := range table {
|
||||
simpleStorage.requestedLabelSelector = nil
|
||||
simpleStorage.requestedFieldSelector = nil
|
||||
simpleStorage.requestedLabelSelector = labels.Everything()
|
||||
simpleStorage.requestedFieldSelector = labels.Everything()
|
||||
simpleStorage.requestedResourceVersion = "5" // Prove this is set in all cases
|
||||
simpleStorage.requestedResourceNamespace = ""
|
||||
dest.RawQuery = item.rawQuery
|
||||
|
25
pkg/client/cache/listwatch_test.go
vendored
25
pkg/client/cache/listwatch_test.go
vendored
@ -48,6 +48,15 @@ func buildResourcePath(prefix, namespace, resource string) string {
|
||||
return path.Join(base, resource)
|
||||
}
|
||||
|
||||
func getHostFieldLabel() string {
|
||||
switch testapi.Version() {
|
||||
case "v1beta1", "v1beta2":
|
||||
return "DesiredState.Host"
|
||||
default:
|
||||
return "Status.Host"
|
||||
}
|
||||
}
|
||||
|
||||
// buildQueryValues is a convenience function for knowing if a namespace should be in a query param or not
|
||||
func buildQueryValues(namespace string, query url.Values) url.Values {
|
||||
v := url.Values{}
|
||||
@ -84,17 +93,17 @@ func TestListWatchesCanList(t *testing.T) {
|
||||
},
|
||||
// pod with "assigned" field selector.
|
||||
{
|
||||
location: buildLocation(buildResourcePath("", api.NamespaceAll, "pods"), buildQueryValues(api.NamespaceAll, url.Values{"fields": []string{"DesiredState.Host="}})),
|
||||
location: buildLocation(buildResourcePath("", api.NamespaceAll, "pods"), buildQueryValues(api.NamespaceAll, url.Values{"fields": []string{getHostFieldLabel() + "="}})),
|
||||
resource: "pods",
|
||||
namespace: api.NamespaceAll,
|
||||
fieldSelector: labels.Set{"DesiredState.Host": ""}.AsSelector(),
|
||||
fieldSelector: labels.Set{getHostFieldLabel(): ""}.AsSelector(),
|
||||
},
|
||||
// pod in namespace "foo"
|
||||
{
|
||||
location: buildLocation(buildResourcePath("", "foo", "pods"), buildQueryValues("foo", url.Values{"fields": []string{"DesiredState.Host="}})),
|
||||
location: buildLocation(buildResourcePath("", "foo", "pods"), buildQueryValues("foo", url.Values{"fields": []string{getHostFieldLabel() + "="}})),
|
||||
resource: "pods",
|
||||
namespace: "foo",
|
||||
fieldSelector: labels.Set{"DesiredState.Host": ""}.AsSelector(),
|
||||
fieldSelector: labels.Set{getHostFieldLabel(): ""}.AsSelector(),
|
||||
},
|
||||
}
|
||||
for _, item := range table {
|
||||
@ -138,19 +147,19 @@ func TestListWatchesCanWatch(t *testing.T) {
|
||||
},
|
||||
// pod with "assigned" field selector.
|
||||
{
|
||||
location: buildLocation(buildResourcePath("watch", api.NamespaceAll, "pods"), buildQueryValues(api.NamespaceAll, url.Values{"fields": []string{"DesiredState.Host="}, "resourceVersion": []string{"0"}})),
|
||||
location: buildLocation(buildResourcePath("watch", api.NamespaceAll, "pods"), buildQueryValues(api.NamespaceAll, url.Values{"fields": []string{getHostFieldLabel() + "="}, "resourceVersion": []string{"0"}})),
|
||||
rv: "0",
|
||||
resource: "pods",
|
||||
namespace: api.NamespaceAll,
|
||||
fieldSelector: labels.Set{"DesiredState.Host": ""}.AsSelector(),
|
||||
fieldSelector: labels.Set{getHostFieldLabel(): ""}.AsSelector(),
|
||||
},
|
||||
// pod with namespace foo and assigned field selector
|
||||
{
|
||||
location: buildLocation(buildResourcePath("watch", "foo", "pods"), buildQueryValues("foo", url.Values{"fields": []string{"DesiredState.Host="}, "resourceVersion": []string{"0"}})),
|
||||
location: buildLocation(buildResourcePath("watch", "foo", "pods"), buildQueryValues("foo", url.Values{"fields": []string{getHostFieldLabel() + "="}, "resourceVersion": []string{"0"}})),
|
||||
rv: "0",
|
||||
resource: "pods",
|
||||
namespace: "foo",
|
||||
fieldSelector: labels.Set{"DesiredState.Host": ""}.AsSelector(),
|
||||
fieldSelector: labels.Set{getHostFieldLabel(): ""}.AsSelector(),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ import (
|
||||
|
||||
// NewSourceApiserver creates a config source that watches and pulls from the apiserver.
|
||||
func NewSourceApiserver(client *client.Client, hostname string, updates chan<- interface{}) {
|
||||
lw := cache.NewListWatchFromClient(client, "pods", api.NamespaceAll, labels.OneTermEqualSelector("Status.Host", hostname))
|
||||
lw := cache.NewListWatchFromClient(client, "pods", api.NamespaceAll, labels.OneTermEqualSelector(getHostFieldLabel(client.APIVersion()), hostname))
|
||||
newSourceApiserverFromLW(lw, updates)
|
||||
}
|
||||
|
||||
@ -51,3 +51,12 @@ func newSourceApiserverFromLW(lw cache.ListerWatcher, updates chan<- interface{}
|
||||
}
|
||||
cache.NewReflector(lw, &api.Pod{}, cache.NewUndeltaStore(send, cache.MetaNamespaceKeyFunc)).Run()
|
||||
}
|
||||
|
||||
func getHostFieldLabel(apiVersion string) string {
|
||||
switch apiVersion {
|
||||
case "v1beta1", "v1beta2":
|
||||
return "DesiredState.Host"
|
||||
default:
|
||||
return "Status.Host"
|
||||
}
|
||||
}
|
||||
|
@ -800,6 +800,21 @@ func SelectorFromSetParse(ls Set) (Selector, error) {
|
||||
// ParseSelector takes a string representing a selector and returns an
|
||||
// object suitable for matching, or an error.
|
||||
func ParseSelector(selector string) (Selector, error) {
|
||||
return parseSelector(selector,
|
||||
func(lhs, rhs string) (newLhs, newRhs string, err error) {
|
||||
return lhs, rhs, nil
|
||||
})
|
||||
}
|
||||
|
||||
// Parses the selector and runs them through the given TransformFunc.
|
||||
func ParseAndTransformSelector(selector string, fn TransformFunc) (Selector, error) {
|
||||
return parseSelector(selector, fn)
|
||||
}
|
||||
|
||||
// Function to transform selectors.
|
||||
type TransformFunc func(label, value string) (newLabel, newValue string, err error)
|
||||
|
||||
func parseSelector(selector string, fn TransformFunc) (Selector, error) {
|
||||
parts := strings.Split(selector, ",")
|
||||
sort.StringSlice(parts).Sort()
|
||||
var items []Selector
|
||||
@ -808,10 +823,22 @@ func ParseSelector(selector string) (Selector, error) {
|
||||
continue
|
||||
}
|
||||
if lhs, rhs, ok := try(part, "!="); ok {
|
||||
lhs, rhs, err := fn(lhs, rhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, ¬HasTerm{label: lhs, value: rhs})
|
||||
} else if lhs, rhs, ok := try(part, "=="); ok {
|
||||
lhs, rhs, err := fn(lhs, rhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, &hasTerm{label: lhs, value: rhs})
|
||||
} else if lhs, rhs, ok := try(part, "="); ok {
|
||||
lhs, rhs, err := fn(lhs, rhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, &hasTerm{label: lhs, value: rhs})
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid selector: '%s'; can't understand '%s'", selector, part)
|
||||
|
@ -23,7 +23,6 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic"
|
||||
@ -120,18 +119,10 @@ func MatchPod(label, field labels.Selector) generic.Matcher {
|
||||
// PodToSelectableFields returns a label set that represents the object
|
||||
// TODO: fields are not labels, and the validation rules for them do not apply.
|
||||
func PodToSelectableFields(pod *api.Pod) labels.Set {
|
||||
// TODO we are populating both Status and DesiredState because selectors are not aware of API versions
|
||||
// see https://github.com/GoogleCloudPlatform/kubernetes/pull/2503
|
||||
|
||||
var olderPodStatus v1beta1.PodStatus
|
||||
api.Scheme.Convert(pod.Status.Phase, &olderPodStatus)
|
||||
|
||||
return labels.Set{
|
||||
"name": pod.Name,
|
||||
"Status.Phase": string(pod.Status.Phase),
|
||||
"Status.Host": pod.Status.Host,
|
||||
"DesiredState.Status": string(olderPodStatus),
|
||||
"DesiredState.Host": pod.Status.Host,
|
||||
"name": pod.Name,
|
||||
"Status.Phase": string(pod.Status.Phase),
|
||||
"Status.Host": pod.Status.Host,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,8 +27,14 @@ import (
|
||||
// is an adaptation of conversion's Scheme for our API objects.
|
||||
type Scheme struct {
|
||||
raw *conversion.Scheme
|
||||
// Map from version and resource to the corresponding func to convert
|
||||
// resource field labels in that version to internal version.
|
||||
fieldLabelConversionFuncs map[string]map[string]FieldLabelConversionFunc
|
||||
}
|
||||
|
||||
// Function to convert a field selector to internal representation.
|
||||
type FieldLabelConversionFunc func(label, value string) (internalLabel, internalValue string, err error)
|
||||
|
||||
// fromScope gets the input version, desired output version, and desired Scheme
|
||||
// from a conversion.Scope.
|
||||
func (self *Scheme) fromScope(s conversion.Scope) (inVersion, outVersion string, scheme *Scheme) {
|
||||
@ -200,7 +206,7 @@ func (self *Scheme) rawExtensionToRuntimeObjectArray(in *[]RawExtension, out *[]
|
||||
|
||||
// NewScheme creates a new Scheme. This scheme is pluggable by default.
|
||||
func NewScheme() *Scheme {
|
||||
s := &Scheme{conversion.NewScheme()}
|
||||
s := &Scheme{conversion.NewScheme(), map[string]map[string]FieldLabelConversionFunc{}}
|
||||
s.raw.InternalVersion = ""
|
||||
s.raw.MetaFactory = conversion.SimpleMetaFactory{BaseFields: []string{"TypeMeta"}, VersionField: "APIVersion", KindField: "Kind"}
|
||||
if err := s.raw.AddConversionFuncs(
|
||||
@ -280,6 +286,17 @@ func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error {
|
||||
return s.raw.AddConversionFuncs(conversionFuncs...)
|
||||
}
|
||||
|
||||
// AddFieldLabelConversionFunc adds a conversion function to convert field selectors
|
||||
// of the given api resource from the given version to internal version representation.
|
||||
func (s *Scheme) AddFieldLabelConversionFunc(version, apiResource string, conversionFunc FieldLabelConversionFunc) error {
|
||||
if s.fieldLabelConversionFuncs[version] == nil {
|
||||
s.fieldLabelConversionFuncs[version] = map[string]FieldLabelConversionFunc{}
|
||||
}
|
||||
|
||||
s.fieldLabelConversionFuncs[version][apiResource] = conversionFunc
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddStructFieldConversion allows you to specify a mechanical copy for a moved
|
||||
// or renamed struct field without writing an entire conversion function. See
|
||||
// the comment in conversion.Converter.SetStructFieldCopy for parameter details.
|
||||
@ -302,6 +319,18 @@ func (s *Scheme) Convert(in, out interface{}) error {
|
||||
return s.raw.Convert(in, out)
|
||||
}
|
||||
|
||||
// Converts the given field label and value for an apiResource field selector from
|
||||
// versioned representation to an unversioned one.
|
||||
func (s *Scheme) ConvertFieldLabel(version, apiResource, label, value string) (string, string, error) {
|
||||
if typeFuncMap, ok := s.fieldLabelConversionFuncs[version]; ok {
|
||||
if conversionFunc, ok := typeFuncMap[apiResource]; ok {
|
||||
return conversionFunc(label, value)
|
||||
}
|
||||
}
|
||||
// Don't fail on types we haven't added conversion funcs for yet.
|
||||
return label, value, nil
|
||||
}
|
||||
|
||||
// ConvertToVersion attempts to convert an input object to its matching Kind in another
|
||||
// version within this scheme. Will return an error if the provided version does not
|
||||
// contain the inKind (or a mapping by name defined with AddKnownTypeWithName). Will also
|
||||
|
@ -163,7 +163,7 @@ func (f *ConfigFactory) CreateFromKeys(predicateKeys, priorityKeys util.StringSe
|
||||
// Returns a cache.ListWatch that finds all pods that need to be
|
||||
// scheduled.
|
||||
func (factory *ConfigFactory) createUnassignedPodLW() *cache.ListWatch {
|
||||
return cache.NewListWatchFromClient(factory.Client, "pods", api.NamespaceAll, labels.Set{"DesiredState.Host": ""}.AsSelector())
|
||||
return cache.NewListWatchFromClient(factory.Client, "pods", api.NamespaceAll, labels.Set{getHostFieldLabel(factory.Client.APIVersion()): ""}.AsSelector())
|
||||
}
|
||||
|
||||
func parseSelectorOrDie(s string) labels.Selector {
|
||||
@ -178,7 +178,8 @@ func parseSelectorOrDie(s string) labels.Selector {
|
||||
// already scheduled.
|
||||
// TODO: return a ListerWatcher interface instead?
|
||||
func (factory *ConfigFactory) createAssignedPodLW() *cache.ListWatch {
|
||||
return cache.NewListWatchFromClient(factory.Client, "pods", api.NamespaceAll, parseSelectorOrDie("DesiredState.Host!="))
|
||||
return cache.NewListWatchFromClient(factory.Client, "pods", api.NamespaceAll,
|
||||
parseSelectorOrDie(getHostFieldLabel(factory.Client.APIVersion())+"!="))
|
||||
}
|
||||
|
||||
// createMinionLW returns a cache.ListWatch that gets all changes to minions.
|
||||
@ -251,7 +252,16 @@ func (factory *ConfigFactory) makeDefaultErrorFunc(backoff *podBackoff, podQueue
|
||||
}
|
||||
}
|
||||
|
||||
// Allows a cache.Poller to enumerate items in an api.NodeList
|
||||
func getHostFieldLabel(apiVersion string) string {
|
||||
switch apiVersion {
|
||||
case "v1beta1", "v1beta2":
|
||||
return "DesiredState.Host"
|
||||
default:
|
||||
return "Status.Host"
|
||||
}
|
||||
}
|
||||
|
||||
// nodeEnumerator allows a cache.Poller to enumerate items in an api.NodeList
|
||||
type nodeEnumerator struct {
|
||||
*api.NodeList
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user