mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 18:43:34 +00:00
vendor files
This commit is contained in:
6
vendor/k8s.io/apimachinery/pkg/OWNERS
generated
vendored
Normal file
6
vendor/k8s.io/apimachinery/pkg/OWNERS
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
approvers:
|
||||
- caesarxuchao
|
||||
- deads2k
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- liggitt
|
32
vendor/k8s.io/apimachinery/pkg/api/equality/BUILD
generated
vendored
Normal file
32
vendor/k8s.io/apimachinery/pkg/api/equality/BUILD
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["semantic.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/equality",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
49
vendor/k8s.io/apimachinery/pkg/api/equality/semantic.go
generated
vendored
Normal file
49
vendor/k8s.io/apimachinery/pkg/api/equality/semantic.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright 2014 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 equality
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
// Semantic can do semantic deep equality checks for api objects.
|
||||
// Example: apiequality.Semantic.DeepEqual(aPod, aPodWithNonNilButEmptyMaps) == true
|
||||
var Semantic = conversion.EqualitiesOrDie(
|
||||
func(a, b resource.Quantity) bool {
|
||||
// Ignore formatting, only care that numeric value stayed the same.
|
||||
// TODO: if we decide it's important, it should be safe to start comparing the format.
|
||||
//
|
||||
// Uninitialized quantities are equivalent to 0 quantities.
|
||||
return a.Cmp(b) == 0
|
||||
},
|
||||
func(a, b metav1.MicroTime) bool {
|
||||
return a.UTC() == b.UTC()
|
||||
},
|
||||
func(a, b metav1.Time) bool {
|
||||
return a.UTC() == b.UTC()
|
||||
},
|
||||
func(a, b labels.Selector) bool {
|
||||
return a.String() == b.String()
|
||||
},
|
||||
func(a, b fields.Selector) bool {
|
||||
return a.String() == b.String()
|
||||
},
|
||||
)
|
48
vendor/k8s.io/apimachinery/pkg/api/errors/BUILD
generated
vendored
Normal file
48
vendor/k8s.io/apimachinery/pkg/api/errors/BUILD
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["errors_test.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/errors",
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"errors.go",
|
||||
],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/errors",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
25
vendor/k8s.io/apimachinery/pkg/api/errors/OWNERS
generated
vendored
Executable file
25
vendor/k8s.io/apimachinery/pkg/api/errors/OWNERS
generated
vendored
Executable file
@ -0,0 +1,25 @@
|
||||
reviewers:
|
||||
- thockin
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- brendandburns
|
||||
- derekwaynecarr
|
||||
- caesarxuchao
|
||||
- mikedanese
|
||||
- liggitt
|
||||
- nikhiljindal
|
||||
- gmarek
|
||||
- erictune
|
||||
- saad-ali
|
||||
- janetkuo
|
||||
- tallclair
|
||||
- eparis
|
||||
- timothysc
|
||||
- dims
|
||||
- hongchaodeng
|
||||
- krousey
|
||||
- cjcullen
|
||||
- david-mcmahon
|
||||
- goltermann
|
18
vendor/k8s.io/apimachinery/pkg/api/errors/doc.go
generated
vendored
Normal file
18
vendor/k8s.io/apimachinery/pkg/api/errors/doc.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright 2014 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 errors provides detailed error types for api field validation.
|
||||
package errors // import "k8s.io/apimachinery/pkg/api/errors"
|
546
vendor/k8s.io/apimachinery/pkg/api/errors/errors.go
generated
vendored
Normal file
546
vendor/k8s.io/apimachinery/pkg/api/errors/errors.go
generated
vendored
Normal file
@ -0,0 +1,546 @@
|
||||
/*
|
||||
Copyright 2014 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 errors
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
const (
|
||||
// StatusTooManyRequests means the server experienced too many requests within a
|
||||
// given window and that the client must wait to perform the action again.
|
||||
StatusTooManyRequests = 429
|
||||
)
|
||||
|
||||
// StatusError is an error intended for consumption by a REST API server; it can also be
|
||||
// reconstructed by clients from a REST response. Public to allow easy type switches.
|
||||
type StatusError struct {
|
||||
ErrStatus metav1.Status
|
||||
}
|
||||
|
||||
// APIStatus is exposed by errors that can be converted to an api.Status object
|
||||
// for finer grained details.
|
||||
type APIStatus interface {
|
||||
Status() metav1.Status
|
||||
}
|
||||
|
||||
var _ error = &StatusError{}
|
||||
|
||||
// Error implements the Error interface.
|
||||
func (e *StatusError) Error() string {
|
||||
return e.ErrStatus.Message
|
||||
}
|
||||
|
||||
// Status allows access to e's status without having to know the detailed workings
|
||||
// of StatusError.
|
||||
func (e *StatusError) Status() metav1.Status {
|
||||
return e.ErrStatus
|
||||
}
|
||||
|
||||
// DebugError reports extended info about the error to debug output.
|
||||
func (e *StatusError) DebugError() (string, []interface{}) {
|
||||
if out, err := json.MarshalIndent(e.ErrStatus, "", " "); err == nil {
|
||||
return "server response object: %s", []interface{}{string(out)}
|
||||
}
|
||||
return "server response object: %#v", []interface{}{e.ErrStatus}
|
||||
}
|
||||
|
||||
// UnexpectedObjectError can be returned by FromObject if it's passed a non-status object.
|
||||
type UnexpectedObjectError struct {
|
||||
Object runtime.Object
|
||||
}
|
||||
|
||||
// Error returns an error message describing 'u'.
|
||||
func (u *UnexpectedObjectError) Error() string {
|
||||
return fmt.Sprintf("unexpected object: %v", u.Object)
|
||||
}
|
||||
|
||||
// FromObject generates an StatusError from an metav1.Status, if that is the type of obj; otherwise,
|
||||
// returns an UnexpecteObjectError.
|
||||
func FromObject(obj runtime.Object) error {
|
||||
switch t := obj.(type) {
|
||||
case *metav1.Status:
|
||||
return &StatusError{*t}
|
||||
}
|
||||
return &UnexpectedObjectError{obj}
|
||||
}
|
||||
|
||||
// NewNotFound returns a new error which indicates that the resource of the kind and the name was not found.
|
||||
func NewNotFound(qualifiedResource schema.GroupResource, name string) *StatusError {
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusNotFound,
|
||||
Reason: metav1.StatusReasonNotFound,
|
||||
Details: &metav1.StatusDetails{
|
||||
Group: qualifiedResource.Group,
|
||||
Kind: qualifiedResource.Resource,
|
||||
Name: name,
|
||||
},
|
||||
Message: fmt.Sprintf("%s %q not found", qualifiedResource.String(), name),
|
||||
}}
|
||||
}
|
||||
|
||||
// NewAlreadyExists returns an error indicating the item requested exists by that identifier.
|
||||
func NewAlreadyExists(qualifiedResource schema.GroupResource, name string) *StatusError {
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusConflict,
|
||||
Reason: metav1.StatusReasonAlreadyExists,
|
||||
Details: &metav1.StatusDetails{
|
||||
Group: qualifiedResource.Group,
|
||||
Kind: qualifiedResource.Resource,
|
||||
Name: name,
|
||||
},
|
||||
Message: fmt.Sprintf("%s %q already exists", qualifiedResource.String(), name),
|
||||
}}
|
||||
}
|
||||
|
||||
// NewUnauthorized returns an error indicating the client is not authorized to perform the requested
|
||||
// action.
|
||||
func NewUnauthorized(reason string) *StatusError {
|
||||
message := reason
|
||||
if len(message) == 0 {
|
||||
message = "not authorized"
|
||||
}
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusUnauthorized,
|
||||
Reason: metav1.StatusReasonUnauthorized,
|
||||
Message: message,
|
||||
}}
|
||||
}
|
||||
|
||||
// NewForbidden returns an error indicating the requested action was forbidden
|
||||
func NewForbidden(qualifiedResource schema.GroupResource, name string, err error) *StatusError {
|
||||
var message string
|
||||
if qualifiedResource.Empty() {
|
||||
message = fmt.Sprintf("forbidden: %v", err)
|
||||
} else if name == "" {
|
||||
message = fmt.Sprintf("%s is forbidden: %v", qualifiedResource.String(), err)
|
||||
} else {
|
||||
message = fmt.Sprintf("%s %q is forbidden: %v", qualifiedResource.String(), name, err)
|
||||
}
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusForbidden,
|
||||
Reason: metav1.StatusReasonForbidden,
|
||||
Details: &metav1.StatusDetails{
|
||||
Group: qualifiedResource.Group,
|
||||
Kind: qualifiedResource.Resource,
|
||||
Name: name,
|
||||
},
|
||||
Message: message,
|
||||
}}
|
||||
}
|
||||
|
||||
// NewConflict returns an error indicating the item can't be updated as provided.
|
||||
func NewConflict(qualifiedResource schema.GroupResource, name string, err error) *StatusError {
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusConflict,
|
||||
Reason: metav1.StatusReasonConflict,
|
||||
Details: &metav1.StatusDetails{
|
||||
Group: qualifiedResource.Group,
|
||||
Kind: qualifiedResource.Resource,
|
||||
Name: name,
|
||||
},
|
||||
Message: fmt.Sprintf("Operation cannot be fulfilled on %s %q: %v", qualifiedResource.String(), name, err),
|
||||
}}
|
||||
}
|
||||
|
||||
// NewGone returns an error indicating the item no longer available at the server and no forwarding address is known.
|
||||
func NewGone(message string) *StatusError {
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusGone,
|
||||
Reason: metav1.StatusReasonGone,
|
||||
Message: message,
|
||||
}}
|
||||
}
|
||||
|
||||
// NewResourceExpired creates an error that indicates that the requested resource content has expired from
|
||||
// the server (usually due to a resourceVersion that is too old).
|
||||
func NewResourceExpired(message string) *StatusError {
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusGone,
|
||||
Reason: metav1.StatusReasonExpired,
|
||||
Message: message,
|
||||
}}
|
||||
}
|
||||
|
||||
// NewInvalid returns an error indicating the item is invalid and cannot be processed.
|
||||
func NewInvalid(qualifiedKind schema.GroupKind, name string, errs field.ErrorList) *StatusError {
|
||||
causes := make([]metav1.StatusCause, 0, len(errs))
|
||||
for i := range errs {
|
||||
err := errs[i]
|
||||
causes = append(causes, metav1.StatusCause{
|
||||
Type: metav1.CauseType(err.Type),
|
||||
Message: err.ErrorBody(),
|
||||
Field: err.Field,
|
||||
})
|
||||
}
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusUnprocessableEntity,
|
||||
Reason: metav1.StatusReasonInvalid,
|
||||
Details: &metav1.StatusDetails{
|
||||
Group: qualifiedKind.Group,
|
||||
Kind: qualifiedKind.Kind,
|
||||
Name: name,
|
||||
Causes: causes,
|
||||
},
|
||||
Message: fmt.Sprintf("%s %q is invalid: %v", qualifiedKind.String(), name, errs.ToAggregate()),
|
||||
}}
|
||||
}
|
||||
|
||||
// NewBadRequest creates an error that indicates that the request is invalid and can not be processed.
|
||||
func NewBadRequest(reason string) *StatusError {
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusBadRequest,
|
||||
Reason: metav1.StatusReasonBadRequest,
|
||||
Message: reason,
|
||||
}}
|
||||
}
|
||||
|
||||
// NewTooManyRequests creates an error that indicates that the client must try again later because
|
||||
// the specified endpoint is not accepting requests. More specific details should be provided
|
||||
// if client should know why the failure was limited4.
|
||||
func NewTooManyRequests(message string, retryAfterSeconds int) *StatusError {
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusTooManyRequests,
|
||||
Reason: metav1.StatusReasonTooManyRequests,
|
||||
Message: message,
|
||||
Details: &metav1.StatusDetails{
|
||||
RetryAfterSeconds: int32(retryAfterSeconds),
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
// NewServiceUnavailable creates an error that indicates that the requested service is unavailable.
|
||||
func NewServiceUnavailable(reason string) *StatusError {
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusServiceUnavailable,
|
||||
Reason: metav1.StatusReasonServiceUnavailable,
|
||||
Message: reason,
|
||||
}}
|
||||
}
|
||||
|
||||
// NewMethodNotSupported returns an error indicating the requested action is not supported on this kind.
|
||||
func NewMethodNotSupported(qualifiedResource schema.GroupResource, action string) *StatusError {
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusMethodNotAllowed,
|
||||
Reason: metav1.StatusReasonMethodNotAllowed,
|
||||
Details: &metav1.StatusDetails{
|
||||
Group: qualifiedResource.Group,
|
||||
Kind: qualifiedResource.Resource,
|
||||
},
|
||||
Message: fmt.Sprintf("%s is not supported on resources of kind %q", action, qualifiedResource.String()),
|
||||
}}
|
||||
}
|
||||
|
||||
// NewServerTimeout returns an error indicating the requested action could not be completed due to a
|
||||
// transient error, and the client should try again.
|
||||
func NewServerTimeout(qualifiedResource schema.GroupResource, operation string, retryAfterSeconds int) *StatusError {
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusInternalServerError,
|
||||
Reason: metav1.StatusReasonServerTimeout,
|
||||
Details: &metav1.StatusDetails{
|
||||
Group: qualifiedResource.Group,
|
||||
Kind: qualifiedResource.Resource,
|
||||
Name: operation,
|
||||
RetryAfterSeconds: int32(retryAfterSeconds),
|
||||
},
|
||||
Message: fmt.Sprintf("The %s operation against %s could not be completed at this time, please try again.", operation, qualifiedResource.String()),
|
||||
}}
|
||||
}
|
||||
|
||||
// NewServerTimeoutForKind should not exist. Server timeouts happen when accessing resources, the Kind is just what we
|
||||
// happened to be looking at when the request failed. This delegates to keep code sane, but we should work towards removing this.
|
||||
func NewServerTimeoutForKind(qualifiedKind schema.GroupKind, operation string, retryAfterSeconds int) *StatusError {
|
||||
return NewServerTimeout(schema.GroupResource{Group: qualifiedKind.Group, Resource: qualifiedKind.Kind}, operation, retryAfterSeconds)
|
||||
}
|
||||
|
||||
// NewInternalError returns an error indicating the item is invalid and cannot be processed.
|
||||
func NewInternalError(err error) *StatusError {
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusInternalServerError,
|
||||
Reason: metav1.StatusReasonInternalError,
|
||||
Details: &metav1.StatusDetails{
|
||||
Causes: []metav1.StatusCause{{Message: err.Error()}},
|
||||
},
|
||||
Message: fmt.Sprintf("Internal error occurred: %v", err),
|
||||
}}
|
||||
}
|
||||
|
||||
// NewTimeoutError returns an error indicating that a timeout occurred before the request
|
||||
// could be completed. Clients may retry, but the operation may still complete.
|
||||
func NewTimeoutError(message string, retryAfterSeconds int) *StatusError {
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusGatewayTimeout,
|
||||
Reason: metav1.StatusReasonTimeout,
|
||||
Message: fmt.Sprintf("Timeout: %s", message),
|
||||
Details: &metav1.StatusDetails{
|
||||
RetryAfterSeconds: int32(retryAfterSeconds),
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
// NewTooManyRequestsError returns an error indicating that the request was rejected because
|
||||
// the server has received too many requests. Client should wait and retry. But if the request
|
||||
// is perishable, then the client should not retry the request.
|
||||
func NewTooManyRequestsError(message string) *StatusError {
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: StatusTooManyRequests,
|
||||
Reason: metav1.StatusReasonTooManyRequests,
|
||||
Message: fmt.Sprintf("Too many requests: %s", message),
|
||||
}}
|
||||
}
|
||||
|
||||
// NewGenericServerResponse returns a new error for server responses that are not in a recognizable form.
|
||||
func NewGenericServerResponse(code int, verb string, qualifiedResource schema.GroupResource, name, serverMessage string, retryAfterSeconds int, isUnexpectedResponse bool) *StatusError {
|
||||
reason := metav1.StatusReasonUnknown
|
||||
message := fmt.Sprintf("the server responded with the status code %d but did not return more information", code)
|
||||
switch code {
|
||||
case http.StatusConflict:
|
||||
if verb == "POST" {
|
||||
reason = metav1.StatusReasonAlreadyExists
|
||||
} else {
|
||||
reason = metav1.StatusReasonConflict
|
||||
}
|
||||
message = "the server reported a conflict"
|
||||
case http.StatusNotFound:
|
||||
reason = metav1.StatusReasonNotFound
|
||||
message = "the server could not find the requested resource"
|
||||
case http.StatusBadRequest:
|
||||
reason = metav1.StatusReasonBadRequest
|
||||
message = "the server rejected our request for an unknown reason"
|
||||
case http.StatusUnauthorized:
|
||||
reason = metav1.StatusReasonUnauthorized
|
||||
message = "the server has asked for the client to provide credentials"
|
||||
case http.StatusForbidden:
|
||||
reason = metav1.StatusReasonForbidden
|
||||
// the server message has details about who is trying to perform what action. Keep its message.
|
||||
message = serverMessage
|
||||
case http.StatusMethodNotAllowed:
|
||||
reason = metav1.StatusReasonMethodNotAllowed
|
||||
message = "the server does not allow this method on the requested resource"
|
||||
case http.StatusUnprocessableEntity:
|
||||
reason = metav1.StatusReasonInvalid
|
||||
message = "the server rejected our request due to an error in our request"
|
||||
case http.StatusGatewayTimeout:
|
||||
reason = metav1.StatusReasonTimeout
|
||||
message = "the server was unable to return a response in the time allotted, but may still be processing the request"
|
||||
case http.StatusTooManyRequests:
|
||||
reason = metav1.StatusReasonTooManyRequests
|
||||
message = "the server has received too many requests and has asked us to try again later"
|
||||
default:
|
||||
if code >= 500 {
|
||||
reason = metav1.StatusReasonInternalError
|
||||
message = fmt.Sprintf("an error on the server (%q) has prevented the request from succeeding", serverMessage)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case !qualifiedResource.Empty() && len(name) > 0:
|
||||
message = fmt.Sprintf("%s (%s %s %s)", message, strings.ToLower(verb), qualifiedResource.String(), name)
|
||||
case !qualifiedResource.Empty():
|
||||
message = fmt.Sprintf("%s (%s %s)", message, strings.ToLower(verb), qualifiedResource.String())
|
||||
}
|
||||
var causes []metav1.StatusCause
|
||||
if isUnexpectedResponse {
|
||||
causes = []metav1.StatusCause{
|
||||
{
|
||||
Type: metav1.CauseTypeUnexpectedServerResponse,
|
||||
Message: serverMessage,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
causes = nil
|
||||
}
|
||||
return &StatusError{metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: int32(code),
|
||||
Reason: reason,
|
||||
Details: &metav1.StatusDetails{
|
||||
Group: qualifiedResource.Group,
|
||||
Kind: qualifiedResource.Resource,
|
||||
Name: name,
|
||||
|
||||
Causes: causes,
|
||||
RetryAfterSeconds: int32(retryAfterSeconds),
|
||||
},
|
||||
Message: message,
|
||||
}}
|
||||
}
|
||||
|
||||
// IsNotFound returns true if the specified error was created by NewNotFound.
|
||||
func IsNotFound(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonNotFound
|
||||
}
|
||||
|
||||
// IsAlreadyExists determines if the err is an error which indicates that a specified resource already exists.
|
||||
func IsAlreadyExists(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonAlreadyExists
|
||||
}
|
||||
|
||||
// IsConflict determines if the err is an error which indicates the provided update conflicts.
|
||||
func IsConflict(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonConflict
|
||||
}
|
||||
|
||||
// IsInvalid determines if the err is an error which indicates the provided resource is not valid.
|
||||
func IsInvalid(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonInvalid
|
||||
}
|
||||
|
||||
// IsGone is true if the error indicates the requested resource is no longer available.
|
||||
func IsGone(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonGone
|
||||
}
|
||||
|
||||
// IsResourceExpired is true if the error indicates the resource has expired and the current action is
|
||||
// no longer possible.
|
||||
func IsResourceExpired(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonExpired
|
||||
}
|
||||
|
||||
// IsMethodNotSupported determines if the err is an error which indicates the provided action could not
|
||||
// be performed because it is not supported by the server.
|
||||
func IsMethodNotSupported(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonMethodNotAllowed
|
||||
}
|
||||
|
||||
// IsServiceUnavailable is true if the error indicates the underlying service is no longer available.
|
||||
func IsServiceUnavailable(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonServiceUnavailable
|
||||
}
|
||||
|
||||
// IsBadRequest determines if err is an error which indicates that the request is invalid.
|
||||
func IsBadRequest(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonBadRequest
|
||||
}
|
||||
|
||||
// IsUnauthorized determines if err is an error which indicates that the request is unauthorized and
|
||||
// requires authentication by the user.
|
||||
func IsUnauthorized(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonUnauthorized
|
||||
}
|
||||
|
||||
// IsForbidden determines if err is an error which indicates that the request is forbidden and cannot
|
||||
// be completed as requested.
|
||||
func IsForbidden(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonForbidden
|
||||
}
|
||||
|
||||
// IsTimeout determines if err is an error which indicates that request times out due to long
|
||||
// processing.
|
||||
func IsTimeout(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonTimeout
|
||||
}
|
||||
|
||||
// IsServerTimeout determines if err is an error which indicates that the request needs to be retried
|
||||
// by the client.
|
||||
func IsServerTimeout(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonServerTimeout
|
||||
}
|
||||
|
||||
// IsInternalError determines if err is an error which indicates an internal server error.
|
||||
func IsInternalError(err error) bool {
|
||||
return ReasonForError(err) == metav1.StatusReasonInternalError
|
||||
}
|
||||
|
||||
// IsTooManyRequests determines if err is an error which indicates that there are too many requests
|
||||
// that the server cannot handle.
|
||||
func IsTooManyRequests(err error) bool {
|
||||
if ReasonForError(err) == metav1.StatusReasonTooManyRequests {
|
||||
return true
|
||||
}
|
||||
switch t := err.(type) {
|
||||
case APIStatus:
|
||||
return t.Status().Code == http.StatusTooManyRequests
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsUnexpectedServerError returns true if the server response was not in the expected API format,
|
||||
// and may be the result of another HTTP actor.
|
||||
func IsUnexpectedServerError(err error) bool {
|
||||
switch t := err.(type) {
|
||||
case APIStatus:
|
||||
if d := t.Status().Details; d != nil {
|
||||
for _, cause := range d.Causes {
|
||||
if cause.Type == metav1.CauseTypeUnexpectedServerResponse {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsUnexpectedObjectError determines if err is due to an unexpected object from the master.
|
||||
func IsUnexpectedObjectError(err error) bool {
|
||||
_, ok := err.(*UnexpectedObjectError)
|
||||
return err != nil && ok
|
||||
}
|
||||
|
||||
// SuggestsClientDelay returns true if this error suggests a client delay as well as the
|
||||
// suggested seconds to wait, or false if the error does not imply a wait. It does not
|
||||
// address whether the error *should* be retried, since some errors (like a 3xx) may
|
||||
// request delay without retry.
|
||||
func SuggestsClientDelay(err error) (int, bool) {
|
||||
switch t := err.(type) {
|
||||
case APIStatus:
|
||||
if t.Status().Details != nil {
|
||||
switch t.Status().Reason {
|
||||
// this StatusReason explicitly requests the caller to delay the action
|
||||
case metav1.StatusReasonServerTimeout:
|
||||
return int(t.Status().Details.RetryAfterSeconds), true
|
||||
}
|
||||
// If the client requests that we retry after a certain number of seconds
|
||||
if t.Status().Details.RetryAfterSeconds > 0 {
|
||||
return int(t.Status().Details.RetryAfterSeconds), true
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// ReasonForError returns the HTTP status for a particular error.
|
||||
func ReasonForError(err error) metav1.StatusReason {
|
||||
switch t := err.(type) {
|
||||
case APIStatus:
|
||||
return t.Status().Reason
|
||||
}
|
||||
return metav1.StatusReasonUnknown
|
||||
}
|
222
vendor/k8s.io/apimachinery/pkg/api/errors/errors_test.go
generated
vendored
Normal file
222
vendor/k8s.io/apimachinery/pkg/api/errors/errors_test.go
generated
vendored
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
Copyright 2014 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 errors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
func resource(resource string) schema.GroupResource {
|
||||
return schema.GroupResource{Group: "", Resource: resource}
|
||||
}
|
||||
func kind(kind string) schema.GroupKind {
|
||||
return schema.GroupKind{Group: "", Kind: kind}
|
||||
}
|
||||
|
||||
func TestErrorNew(t *testing.T) {
|
||||
err := NewAlreadyExists(resource("tests"), "1")
|
||||
if !IsAlreadyExists(err) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonAlreadyExists)
|
||||
}
|
||||
if IsConflict(err) {
|
||||
t.Errorf("expected to not be %s", metav1.StatusReasonConflict)
|
||||
}
|
||||
if IsNotFound(err) {
|
||||
t.Errorf(fmt.Sprintf("expected to not be %s", metav1.StatusReasonNotFound))
|
||||
}
|
||||
if IsInvalid(err) {
|
||||
t.Errorf("expected to not be %s", metav1.StatusReasonInvalid)
|
||||
}
|
||||
if IsBadRequest(err) {
|
||||
t.Errorf("expected to not be %s", metav1.StatusReasonBadRequest)
|
||||
}
|
||||
if IsForbidden(err) {
|
||||
t.Errorf("expected to not be %s", metav1.StatusReasonForbidden)
|
||||
}
|
||||
if IsServerTimeout(err) {
|
||||
t.Errorf("expected to not be %s", metav1.StatusReasonServerTimeout)
|
||||
}
|
||||
if IsMethodNotSupported(err) {
|
||||
t.Errorf("expected to not be %s", metav1.StatusReasonMethodNotAllowed)
|
||||
}
|
||||
|
||||
if !IsConflict(NewConflict(resource("tests"), "2", errors.New("message"))) {
|
||||
t.Errorf("expected to be conflict")
|
||||
}
|
||||
if !IsNotFound(NewNotFound(resource("tests"), "3")) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonNotFound)
|
||||
}
|
||||
if !IsInvalid(NewInvalid(kind("Test"), "2", nil)) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonInvalid)
|
||||
}
|
||||
if !IsBadRequest(NewBadRequest("reason")) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonBadRequest)
|
||||
}
|
||||
if !IsForbidden(NewForbidden(resource("tests"), "2", errors.New("reason"))) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonForbidden)
|
||||
}
|
||||
if !IsUnauthorized(NewUnauthorized("reason")) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonUnauthorized)
|
||||
}
|
||||
if !IsServerTimeout(NewServerTimeout(resource("tests"), "reason", 0)) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonServerTimeout)
|
||||
}
|
||||
if !IsMethodNotSupported(NewMethodNotSupported(resource("foos"), "delete")) {
|
||||
t.Errorf("expected to be %s", metav1.StatusReasonMethodNotAllowed)
|
||||
}
|
||||
|
||||
if time, ok := SuggestsClientDelay(NewServerTimeout(resource("tests"), "doing something", 10)); time != 10 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewServerTimeout(resource("tests"), "doing something", 0)); time != 0 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewTimeoutError("test reason", 10)); time != 10 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewTooManyRequests("doing something", 10)); time != 10 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewTooManyRequests("doing something", 1)); time != 1 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewGenericServerResponse(429, "get", resource("tests"), "test", "doing something", 10, true)); time != 10 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewGenericServerResponse(500, "get", resource("tests"), "test", "doing something", 10, true)); time != 10 || !ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
if time, ok := SuggestsClientDelay(NewGenericServerResponse(429, "get", resource("tests"), "test", "doing something", 0, true)); time != 0 || ok {
|
||||
t.Errorf("unexpected %d", time)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewInvalid(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Err *field.Error
|
||||
Details *metav1.StatusDetails
|
||||
}{
|
||||
{
|
||||
field.Duplicate(field.NewPath("field[0].name"), "bar"),
|
||||
&metav1.StatusDetails{
|
||||
Kind: "Kind",
|
||||
Name: "name",
|
||||
Causes: []metav1.StatusCause{{
|
||||
Type: metav1.CauseTypeFieldValueDuplicate,
|
||||
Field: "field[0].name",
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
field.Invalid(field.NewPath("field[0].name"), "bar", "detail"),
|
||||
&metav1.StatusDetails{
|
||||
Kind: "Kind",
|
||||
Name: "name",
|
||||
Causes: []metav1.StatusCause{{
|
||||
Type: metav1.CauseTypeFieldValueInvalid,
|
||||
Field: "field[0].name",
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
field.NotFound(field.NewPath("field[0].name"), "bar"),
|
||||
&metav1.StatusDetails{
|
||||
Kind: "Kind",
|
||||
Name: "name",
|
||||
Causes: []metav1.StatusCause{{
|
||||
Type: metav1.CauseTypeFieldValueNotFound,
|
||||
Field: "field[0].name",
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
field.NotSupported(field.NewPath("field[0].name"), "bar", nil),
|
||||
&metav1.StatusDetails{
|
||||
Kind: "Kind",
|
||||
Name: "name",
|
||||
Causes: []metav1.StatusCause{{
|
||||
Type: metav1.CauseTypeFieldValueNotSupported,
|
||||
Field: "field[0].name",
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
field.Required(field.NewPath("field[0].name"), ""),
|
||||
&metav1.StatusDetails{
|
||||
Kind: "Kind",
|
||||
Name: "name",
|
||||
Causes: []metav1.StatusCause{{
|
||||
Type: metav1.CauseTypeFieldValueRequired,
|
||||
Field: "field[0].name",
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
vErr, expected := testCase.Err, testCase.Details
|
||||
expected.Causes[0].Message = vErr.ErrorBody()
|
||||
err := NewInvalid(kind("Kind"), "name", field.ErrorList{vErr})
|
||||
status := err.ErrStatus
|
||||
if status.Code != 422 || status.Reason != metav1.StatusReasonInvalid {
|
||||
t.Errorf("%d: unexpected status: %#v", i, status)
|
||||
}
|
||||
if !reflect.DeepEqual(expected, status.Details) {
|
||||
t.Errorf("%d: expected %#v, got %#v", i, expected, status.Details)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReasonForError(t *testing.T) {
|
||||
if e, a := metav1.StatusReasonUnknown, ReasonForError(nil); e != a {
|
||||
t.Errorf("unexpected reason type: %#v", a)
|
||||
}
|
||||
}
|
||||
|
||||
type TestType struct{}
|
||||
|
||||
func (obj *TestType) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind }
|
||||
func (obj *TestType) DeepCopyObject() runtime.Object {
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
clone := *obj
|
||||
return &clone
|
||||
}
|
||||
|
||||
func TestFromObject(t *testing.T) {
|
||||
table := []struct {
|
||||
obj runtime.Object
|
||||
message string
|
||||
}{
|
||||
{&metav1.Status{Message: "foobar"}, "foobar"},
|
||||
{&TestType{}, "unexpected object: &{}"},
|
||||
}
|
||||
|
||||
for _, item := range table {
|
||||
if e, a := item.message, FromObject(item.obj).Error(); e != a {
|
||||
t.Errorf("Expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
}
|
69
vendor/k8s.io/apimachinery/pkg/api/meta/BUILD
generated
vendored
Normal file
69
vendor/k8s.io/apimachinery/pkg/api/meta/BUILD
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"meta_test.go",
|
||||
"multirestmapper_test.go",
|
||||
"priority_test.go",
|
||||
"restmapper_test.go",
|
||||
],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/meta",
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"errors.go",
|
||||
"firsthit_restmapper.go",
|
||||
"help.go",
|
||||
"interfaces.go",
|
||||
"lazy.go",
|
||||
"meta.go",
|
||||
"multirestmapper.go",
|
||||
"priority.go",
|
||||
"restmapper.go",
|
||||
"unstructured.go",
|
||||
],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/meta",
|
||||
deps = [
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
25
vendor/k8s.io/apimachinery/pkg/api/meta/OWNERS
generated
vendored
Executable file
25
vendor/k8s.io/apimachinery/pkg/api/meta/OWNERS
generated
vendored
Executable file
@ -0,0 +1,25 @@
|
||||
reviewers:
|
||||
- thockin
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- brendandburns
|
||||
- derekwaynecarr
|
||||
- caesarxuchao
|
||||
- mikedanese
|
||||
- liggitt
|
||||
- nikhiljindal
|
||||
- gmarek
|
||||
- janetkuo
|
||||
- ncdc
|
||||
- eparis
|
||||
- dims
|
||||
- krousey
|
||||
- markturansky
|
||||
- fabioy
|
||||
- resouer
|
||||
- david-mcmahon
|
||||
- mfojtik
|
||||
- jianhuiz
|
||||
- feihujiang
|
||||
- ghodss
|
19
vendor/k8s.io/apimachinery/pkg/api/meta/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/apimachinery/pkg/api/meta/doc.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2014 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 meta provides functions for retrieving API metadata from objects
|
||||
// belonging to the Kubernetes API
|
||||
package meta // import "k8s.io/apimachinery/pkg/api/meta"
|
105
vendor/k8s.io/apimachinery/pkg/api/meta/errors.go
generated
vendored
Normal file
105
vendor/k8s.io/apimachinery/pkg/api/meta/errors.go
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
Copyright 2014 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 meta
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// AmbiguousResourceError is returned if the RESTMapper finds multiple matches for a resource
|
||||
type AmbiguousResourceError struct {
|
||||
PartialResource schema.GroupVersionResource
|
||||
|
||||
MatchingResources []schema.GroupVersionResource
|
||||
MatchingKinds []schema.GroupVersionKind
|
||||
}
|
||||
|
||||
func (e *AmbiguousResourceError) Error() string {
|
||||
switch {
|
||||
case len(e.MatchingKinds) > 0 && len(e.MatchingResources) > 0:
|
||||
return fmt.Sprintf("%v matches multiple resources %v and kinds %v", e.PartialResource, e.MatchingResources, e.MatchingKinds)
|
||||
case len(e.MatchingKinds) > 0:
|
||||
return fmt.Sprintf("%v matches multiple kinds %v", e.PartialResource, e.MatchingKinds)
|
||||
case len(e.MatchingResources) > 0:
|
||||
return fmt.Sprintf("%v matches multiple resources %v", e.PartialResource, e.MatchingResources)
|
||||
}
|
||||
return fmt.Sprintf("%v matches multiple resources or kinds", e.PartialResource)
|
||||
}
|
||||
|
||||
// AmbiguousKindError is returned if the RESTMapper finds multiple matches for a kind
|
||||
type AmbiguousKindError struct {
|
||||
PartialKind schema.GroupVersionKind
|
||||
|
||||
MatchingResources []schema.GroupVersionResource
|
||||
MatchingKinds []schema.GroupVersionKind
|
||||
}
|
||||
|
||||
func (e *AmbiguousKindError) Error() string {
|
||||
switch {
|
||||
case len(e.MatchingKinds) > 0 && len(e.MatchingResources) > 0:
|
||||
return fmt.Sprintf("%v matches multiple resources %v and kinds %v", e.PartialKind, e.MatchingResources, e.MatchingKinds)
|
||||
case len(e.MatchingKinds) > 0:
|
||||
return fmt.Sprintf("%v matches multiple kinds %v", e.PartialKind, e.MatchingKinds)
|
||||
case len(e.MatchingResources) > 0:
|
||||
return fmt.Sprintf("%v matches multiple resources %v", e.PartialKind, e.MatchingResources)
|
||||
}
|
||||
return fmt.Sprintf("%v matches multiple resources or kinds", e.PartialKind)
|
||||
}
|
||||
|
||||
func IsAmbiguousError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
switch err.(type) {
|
||||
case *AmbiguousResourceError, *AmbiguousKindError:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// NoResourceMatchError is returned if the RESTMapper can't find any match for a resource
|
||||
type NoResourceMatchError struct {
|
||||
PartialResource schema.GroupVersionResource
|
||||
}
|
||||
|
||||
func (e *NoResourceMatchError) Error() string {
|
||||
return fmt.Sprintf("no matches for %v", e.PartialResource)
|
||||
}
|
||||
|
||||
// NoKindMatchError is returned if the RESTMapper can't find any match for a kind
|
||||
type NoKindMatchError struct {
|
||||
PartialKind schema.GroupVersionKind
|
||||
}
|
||||
|
||||
func (e *NoKindMatchError) Error() string {
|
||||
return fmt.Sprintf("no matches for %v", e.PartialKind)
|
||||
}
|
||||
|
||||
func IsNoMatchError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
switch err.(type) {
|
||||
case *NoResourceMatchError, *NoKindMatchError:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
97
vendor/k8s.io/apimachinery/pkg/api/meta/firsthit_restmapper.go
generated
vendored
Normal file
97
vendor/k8s.io/apimachinery/pkg/api/meta/firsthit_restmapper.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
Copyright 2014 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 meta
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
)
|
||||
|
||||
// FirstHitRESTMapper is a wrapper for multiple RESTMappers which returns the
|
||||
// first successful result for the singular requests
|
||||
type FirstHitRESTMapper struct {
|
||||
MultiRESTMapper
|
||||
}
|
||||
|
||||
func (m FirstHitRESTMapper) String() string {
|
||||
return fmt.Sprintf("FirstHitRESTMapper{\n\t%v\n}", m.MultiRESTMapper)
|
||||
}
|
||||
|
||||
func (m FirstHitRESTMapper) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
|
||||
errors := []error{}
|
||||
for _, t := range m.MultiRESTMapper {
|
||||
ret, err := t.ResourceFor(resource)
|
||||
if err == nil {
|
||||
return ret, nil
|
||||
}
|
||||
errors = append(errors, err)
|
||||
}
|
||||
|
||||
return schema.GroupVersionResource{}, collapseAggregateErrors(errors)
|
||||
}
|
||||
|
||||
func (m FirstHitRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||
errors := []error{}
|
||||
for _, t := range m.MultiRESTMapper {
|
||||
ret, err := t.KindFor(resource)
|
||||
if err == nil {
|
||||
return ret, nil
|
||||
}
|
||||
errors = append(errors, err)
|
||||
}
|
||||
|
||||
return schema.GroupVersionKind{}, collapseAggregateErrors(errors)
|
||||
}
|
||||
|
||||
// RESTMapping provides the REST mapping for the resource based on the
|
||||
// kind and version. This implementation supports multiple REST schemas and
|
||||
// return the first match.
|
||||
func (m FirstHitRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error) {
|
||||
errors := []error{}
|
||||
for _, t := range m.MultiRESTMapper {
|
||||
ret, err := t.RESTMapping(gk, versions...)
|
||||
if err == nil {
|
||||
return ret, nil
|
||||
}
|
||||
errors = append(errors, err)
|
||||
}
|
||||
|
||||
return nil, collapseAggregateErrors(errors)
|
||||
}
|
||||
|
||||
// collapseAggregateErrors returns the minimal errors. it handles empty as nil, handles one item in a list
|
||||
// by returning the item, and collapses all NoMatchErrors to a single one (since they should all be the same)
|
||||
func collapseAggregateErrors(errors []error) error {
|
||||
if len(errors) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(errors) == 1 {
|
||||
return errors[0]
|
||||
}
|
||||
|
||||
allNoMatchErrors := true
|
||||
for _, err := range errors {
|
||||
allNoMatchErrors = allNoMatchErrors && IsNoMatchError(err)
|
||||
}
|
||||
if allNoMatchErrors {
|
||||
return errors[0]
|
||||
}
|
||||
|
||||
return utilerrors.NewAggregate(errors)
|
||||
}
|
205
vendor/k8s.io/apimachinery/pkg/api/meta/help.go
generated
vendored
Normal file
205
vendor/k8s.io/apimachinery/pkg/api/meta/help.go
generated
vendored
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
Copyright 2015 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 meta
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// IsListType returns true if the provided Object has a slice called Items
|
||||
func IsListType(obj runtime.Object) bool {
|
||||
// if we're a runtime.Unstructured, check whether this is a list.
|
||||
// TODO: refactor GetItemsPtr to use an interface that returns []runtime.Object
|
||||
if unstructured, ok := obj.(runtime.Unstructured); ok {
|
||||
return unstructured.IsList()
|
||||
}
|
||||
|
||||
_, err := GetItemsPtr(obj)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// GetItemsPtr returns a pointer to the list object's Items member.
|
||||
// If 'list' doesn't have an Items member, it's not really a list type
|
||||
// and an error will be returned.
|
||||
// This function will either return a pointer to a slice, or an error, but not both.
|
||||
func GetItemsPtr(list runtime.Object) (interface{}, error) {
|
||||
v, err := conversion.EnforcePtr(list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := v.FieldByName("Items")
|
||||
if !items.IsValid() {
|
||||
return nil, fmt.Errorf("no Items field in %#v", list)
|
||||
}
|
||||
switch items.Kind() {
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
target := reflect.TypeOf(items.Interface()).Elem()
|
||||
if target.Kind() != reflect.Slice {
|
||||
return nil, fmt.Errorf("items: Expected slice, got %s", target.Kind())
|
||||
}
|
||||
return items.Interface(), nil
|
||||
case reflect.Slice:
|
||||
return items.Addr().Interface(), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("items: Expected slice, got %s", items.Kind())
|
||||
}
|
||||
}
|
||||
|
||||
// EachListItem invokes fn on each runtime.Object in the list. Any error immediately terminates
|
||||
// the loop.
|
||||
func EachListItem(obj runtime.Object, fn func(runtime.Object) error) error {
|
||||
if unstructured, ok := obj.(runtime.Unstructured); ok {
|
||||
return unstructured.EachListItem(fn)
|
||||
}
|
||||
// TODO: Change to an interface call?
|
||||
itemsPtr, err := GetItemsPtr(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
items, err := conversion.EnforcePtr(itemsPtr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
len := items.Len()
|
||||
if len == 0 {
|
||||
return nil
|
||||
}
|
||||
takeAddr := false
|
||||
if elemType := items.Type().Elem(); elemType.Kind() != reflect.Ptr && elemType.Kind() != reflect.Interface {
|
||||
if !items.Index(0).CanAddr() {
|
||||
return fmt.Errorf("unable to take address of items in %T for EachListItem", obj)
|
||||
}
|
||||
takeAddr = true
|
||||
}
|
||||
|
||||
for i := 0; i < len; i++ {
|
||||
raw := items.Index(i)
|
||||
if takeAddr {
|
||||
raw = raw.Addr()
|
||||
}
|
||||
switch item := raw.Interface().(type) {
|
||||
case *runtime.RawExtension:
|
||||
if err := fn(item.Object); err != nil {
|
||||
return err
|
||||
}
|
||||
case runtime.Object:
|
||||
if err := fn(item); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
obj, ok := item.(runtime.Object)
|
||||
if !ok {
|
||||
return fmt.Errorf("%v: item[%v]: Expected object, got %#v(%s)", obj, i, raw.Interface(), raw.Kind())
|
||||
}
|
||||
if err := fn(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtractList returns obj's Items element as an array of runtime.Objects.
|
||||
// Returns an error if obj is not a List type (does not have an Items member).
|
||||
func ExtractList(obj runtime.Object) ([]runtime.Object, error) {
|
||||
itemsPtr, err := GetItemsPtr(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items, err := conversion.EnforcePtr(itemsPtr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list := make([]runtime.Object, items.Len())
|
||||
for i := range list {
|
||||
raw := items.Index(i)
|
||||
switch item := raw.Interface().(type) {
|
||||
case runtime.RawExtension:
|
||||
switch {
|
||||
case item.Object != nil:
|
||||
list[i] = item.Object
|
||||
case item.Raw != nil:
|
||||
// TODO: Set ContentEncoding and ContentType correctly.
|
||||
list[i] = &runtime.Unknown{Raw: item.Raw}
|
||||
default:
|
||||
list[i] = nil
|
||||
}
|
||||
case runtime.Object:
|
||||
list[i] = item
|
||||
default:
|
||||
var found bool
|
||||
if list[i], found = raw.Addr().Interface().(runtime.Object); !found {
|
||||
return nil, fmt.Errorf("%v: item[%v]: Expected object, got %#v(%s)", obj, i, raw.Interface(), raw.Kind())
|
||||
}
|
||||
}
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// objectSliceType is the type of a slice of Objects
|
||||
var objectSliceType = reflect.TypeOf([]runtime.Object{})
|
||||
|
||||
// SetList sets the given list object's Items member have the elements given in
|
||||
// objects.
|
||||
// Returns an error if list is not a List type (does not have an Items member),
|
||||
// or if any of the objects are not of the right type.
|
||||
func SetList(list runtime.Object, objects []runtime.Object) error {
|
||||
itemsPtr, err := GetItemsPtr(list)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
items, err := conversion.EnforcePtr(itemsPtr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if items.Type() == objectSliceType {
|
||||
items.Set(reflect.ValueOf(objects))
|
||||
return nil
|
||||
}
|
||||
slice := reflect.MakeSlice(items.Type(), len(objects), len(objects))
|
||||
for i := range objects {
|
||||
dest := slice.Index(i)
|
||||
if dest.Type() == reflect.TypeOf(runtime.RawExtension{}) {
|
||||
dest = dest.FieldByName("Object")
|
||||
}
|
||||
|
||||
// check to see if you're directly assignable
|
||||
if reflect.TypeOf(objects[i]).AssignableTo(dest.Type()) {
|
||||
dest.Set(reflect.ValueOf(objects[i]))
|
||||
continue
|
||||
}
|
||||
|
||||
src, err := conversion.EnforcePtr(objects[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if src.Type().AssignableTo(dest.Type()) {
|
||||
dest.Set(src)
|
||||
} else if src.Type().ConvertibleTo(dest.Type()) {
|
||||
dest.Set(src.Convert(dest.Type()))
|
||||
} else {
|
||||
return fmt.Errorf("item[%d]: can't assign or convert %v into %v", i, src.Type(), dest.Type())
|
||||
}
|
||||
}
|
||||
items.Set(slice)
|
||||
return nil
|
||||
}
|
149
vendor/k8s.io/apimachinery/pkg/api/meta/interfaces.go
generated
vendored
Normal file
149
vendor/k8s.io/apimachinery/pkg/api/meta/interfaces.go
generated
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
Copyright 2014 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 meta
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// VersionInterfaces contains the interfaces one should use for dealing with types of a particular version.
|
||||
type VersionInterfaces struct {
|
||||
runtime.ObjectConvertor
|
||||
MetadataAccessor
|
||||
}
|
||||
|
||||
type ListMetaAccessor interface {
|
||||
GetListMeta() List
|
||||
}
|
||||
|
||||
// List lets you work with list metadata from any of the versioned or
|
||||
// internal API objects. Attempting to set or retrieve a field on an object that does
|
||||
// not support that field will be a no-op and return a default value.
|
||||
type List metav1.ListInterface
|
||||
|
||||
// Type exposes the type and APIVersion of versioned or internal API objects.
|
||||
type Type metav1.Type
|
||||
|
||||
// MetadataAccessor lets you work with object and list metadata from any of the versioned or
|
||||
// internal API objects. Attempting to set or retrieve a field on an object that does
|
||||
// not support that field (Name, UID, Namespace on lists) will be a no-op and return
|
||||
// a default value.
|
||||
//
|
||||
// MetadataAccessor exposes Interface in a way that can be used with multiple objects.
|
||||
type MetadataAccessor interface {
|
||||
APIVersion(obj runtime.Object) (string, error)
|
||||
SetAPIVersion(obj runtime.Object, version string) error
|
||||
|
||||
Kind(obj runtime.Object) (string, error)
|
||||
SetKind(obj runtime.Object, kind string) error
|
||||
|
||||
Namespace(obj runtime.Object) (string, error)
|
||||
SetNamespace(obj runtime.Object, namespace string) error
|
||||
|
||||
Name(obj runtime.Object) (string, error)
|
||||
SetName(obj runtime.Object, name string) error
|
||||
|
||||
GenerateName(obj runtime.Object) (string, error)
|
||||
SetGenerateName(obj runtime.Object, name string) error
|
||||
|
||||
UID(obj runtime.Object) (types.UID, error)
|
||||
SetUID(obj runtime.Object, uid types.UID) error
|
||||
|
||||
SelfLink(obj runtime.Object) (string, error)
|
||||
SetSelfLink(obj runtime.Object, selfLink string) error
|
||||
|
||||
Labels(obj runtime.Object) (map[string]string, error)
|
||||
SetLabels(obj runtime.Object, labels map[string]string) error
|
||||
|
||||
Annotations(obj runtime.Object) (map[string]string, error)
|
||||
SetAnnotations(obj runtime.Object, annotations map[string]string) error
|
||||
|
||||
Continue(obj runtime.Object) (string, error)
|
||||
SetContinue(obj runtime.Object, c string) error
|
||||
|
||||
runtime.ResourceVersioner
|
||||
}
|
||||
|
||||
type RESTScopeName string
|
||||
|
||||
const (
|
||||
RESTScopeNameNamespace RESTScopeName = "namespace"
|
||||
RESTScopeNameRoot RESTScopeName = "root"
|
||||
)
|
||||
|
||||
// RESTScope contains the information needed to deal with REST resources that are in a resource hierarchy
|
||||
type RESTScope interface {
|
||||
// Name of the scope
|
||||
Name() RESTScopeName
|
||||
// ParamName is the optional name of the parameter that should be inserted in the resource url
|
||||
// If empty, no param will be inserted
|
||||
ParamName() string
|
||||
// ArgumentName is the optional name that should be used for the variable holding the value.
|
||||
ArgumentName() string
|
||||
// ParamDescription is the optional description to use to document the parameter in api documentation
|
||||
ParamDescription() string
|
||||
}
|
||||
|
||||
// RESTMapping contains the information needed to deal with objects of a specific
|
||||
// resource and kind in a RESTful manner.
|
||||
type RESTMapping struct {
|
||||
// Resource is a string representing the name of this resource as a REST client would see it
|
||||
Resource string
|
||||
|
||||
GroupVersionKind schema.GroupVersionKind
|
||||
|
||||
// Scope contains the information needed to deal with REST Resources that are in a resource hierarchy
|
||||
Scope RESTScope
|
||||
|
||||
runtime.ObjectConvertor
|
||||
MetadataAccessor
|
||||
}
|
||||
|
||||
// RESTMapper allows clients to map resources to kind, and map kind and version
|
||||
// to interfaces for manipulating those objects. It is primarily intended for
|
||||
// consumers of Kubernetes compatible REST APIs as defined in docs/devel/api-conventions.md.
|
||||
//
|
||||
// The Kubernetes API provides versioned resources and object kinds which are scoped
|
||||
// to API groups. In other words, kinds and resources should not be assumed to be
|
||||
// unique across groups.
|
||||
//
|
||||
// TODO: split into sub-interfaces
|
||||
type RESTMapper interface {
|
||||
// KindFor takes a partial resource and returns the single match. Returns an error if there are multiple matches
|
||||
KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error)
|
||||
|
||||
// KindsFor takes a partial resource and returns the list of potential kinds in priority order
|
||||
KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error)
|
||||
|
||||
// ResourceFor takes a partial resource and returns the single match. Returns an error if there are multiple matches
|
||||
ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error)
|
||||
|
||||
// ResourcesFor takes a partial resource and returns the list of potential resource in priority order
|
||||
ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error)
|
||||
|
||||
// RESTMapping identifies a preferred resource mapping for the provided group kind.
|
||||
RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error)
|
||||
// RESTMappings returns all resource mappings for the provided group kind if no
|
||||
// version search is provided. Otherwise identifies a preferred resource mapping for
|
||||
// the provided version(s).
|
||||
RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error)
|
||||
|
||||
ResourceSingularizer(resource string) (singular string, err error)
|
||||
}
|
121
vendor/k8s.io/apimachinery/pkg/api/meta/lazy.go
generated
vendored
Normal file
121
vendor/k8s.io/apimachinery/pkg/api/meta/lazy.go
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
Copyright 2017 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 meta
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// lazyObject defers loading the mapper and typer until necessary.
|
||||
type lazyObject struct {
|
||||
loader func() (RESTMapper, runtime.ObjectTyper, error)
|
||||
|
||||
lock sync.Mutex
|
||||
loaded bool
|
||||
err error
|
||||
mapper RESTMapper
|
||||
typer runtime.ObjectTyper
|
||||
}
|
||||
|
||||
// NewLazyObjectLoader handles unrecoverable errors when creating a RESTMapper / ObjectTyper by
|
||||
// returning those initialization errors when the interface methods are invoked. This defers the
|
||||
// initialization and any server calls until a client actually needs to perform the action.
|
||||
func NewLazyObjectLoader(fn func() (RESTMapper, runtime.ObjectTyper, error)) (RESTMapper, runtime.ObjectTyper) {
|
||||
obj := &lazyObject{loader: fn}
|
||||
return obj, obj
|
||||
}
|
||||
|
||||
// init lazily loads the mapper and typer, returning an error if initialization has failed.
|
||||
func (o *lazyObject) init() error {
|
||||
o.lock.Lock()
|
||||
defer o.lock.Unlock()
|
||||
if o.loaded {
|
||||
return o.err
|
||||
}
|
||||
o.mapper, o.typer, o.err = o.loader()
|
||||
o.loaded = true
|
||||
return o.err
|
||||
}
|
||||
|
||||
var _ RESTMapper = &lazyObject{}
|
||||
var _ runtime.ObjectTyper = &lazyObject{}
|
||||
|
||||
func (o *lazyObject) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return schema.GroupVersionKind{}, err
|
||||
}
|
||||
return o.mapper.KindFor(resource)
|
||||
}
|
||||
|
||||
func (o *lazyObject) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return []schema.GroupVersionKind{}, err
|
||||
}
|
||||
return o.mapper.KindsFor(resource)
|
||||
}
|
||||
|
||||
func (o *lazyObject) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return schema.GroupVersionResource{}, err
|
||||
}
|
||||
return o.mapper.ResourceFor(input)
|
||||
}
|
||||
|
||||
func (o *lazyObject) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return []schema.GroupVersionResource{}, err
|
||||
}
|
||||
return o.mapper.ResourcesFor(input)
|
||||
}
|
||||
|
||||
func (o *lazyObject) RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return o.mapper.RESTMapping(gk, versions...)
|
||||
}
|
||||
|
||||
func (o *lazyObject) RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return o.mapper.RESTMappings(gk, versions...)
|
||||
}
|
||||
|
||||
func (o *lazyObject) ResourceSingularizer(resource string) (singular string, err error) {
|
||||
if err := o.init(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return o.mapper.ResourceSingularizer(resource)
|
||||
}
|
||||
|
||||
func (o *lazyObject) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return o.typer.ObjectKinds(obj)
|
||||
}
|
||||
|
||||
func (o *lazyObject) Recognizes(gvk schema.GroupVersionKind) bool {
|
||||
if err := o.init(); err != nil {
|
||||
return false
|
||||
}
|
||||
return o.typer.Recognizes(gvk)
|
||||
}
|
653
vendor/k8s.io/apimachinery/pkg/api/meta/meta.go
generated
vendored
Normal file
653
vendor/k8s.io/apimachinery/pkg/api/meta/meta.go
generated
vendored
Normal file
@ -0,0 +1,653 @@
|
||||
/*
|
||||
Copyright 2014 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 meta
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1alpha1 "k8s.io/apimachinery/pkg/apis/meta/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// errNotList is returned when an object implements the Object style interfaces but not the List style
|
||||
// interfaces.
|
||||
var errNotList = fmt.Errorf("object does not implement the List interfaces")
|
||||
|
||||
var errNotCommon = fmt.Errorf("object does not implement the common interface for accessing the SelfLink")
|
||||
|
||||
// CommonAccessor returns a Common interface for the provided object or an error if the object does
|
||||
// not provide List.
|
||||
// TODO: return bool instead of error
|
||||
func CommonAccessor(obj interface{}) (metav1.Common, error) {
|
||||
switch t := obj.(type) {
|
||||
case List:
|
||||
return t, nil
|
||||
case metav1.ListInterface:
|
||||
return t, nil
|
||||
case ListMetaAccessor:
|
||||
if m := t.GetListMeta(); m != nil {
|
||||
return m, nil
|
||||
}
|
||||
return nil, errNotCommon
|
||||
case metav1.ListMetaAccessor:
|
||||
if m := t.GetListMeta(); m != nil {
|
||||
return m, nil
|
||||
}
|
||||
return nil, errNotCommon
|
||||
case metav1.Object:
|
||||
return t, nil
|
||||
case metav1.ObjectMetaAccessor:
|
||||
if m := t.GetObjectMeta(); m != nil {
|
||||
return m, nil
|
||||
}
|
||||
return nil, errNotCommon
|
||||
default:
|
||||
return nil, errNotCommon
|
||||
}
|
||||
}
|
||||
|
||||
// ListAccessor returns a List interface for the provided object or an error if the object does
|
||||
// not provide List.
|
||||
// IMPORTANT: Objects are NOT a superset of lists. Do not use this check to determine whether an
|
||||
// object *is* a List.
|
||||
// TODO: return bool instead of error
|
||||
func ListAccessor(obj interface{}) (List, error) {
|
||||
switch t := obj.(type) {
|
||||
case List:
|
||||
return t, nil
|
||||
case metav1.ListInterface:
|
||||
return t, nil
|
||||
case ListMetaAccessor:
|
||||
if m := t.GetListMeta(); m != nil {
|
||||
return m, nil
|
||||
}
|
||||
return nil, errNotList
|
||||
case metav1.ListMetaAccessor:
|
||||
if m := t.GetListMeta(); m != nil {
|
||||
return m, nil
|
||||
}
|
||||
return nil, errNotList
|
||||
default:
|
||||
return nil, errNotList
|
||||
}
|
||||
}
|
||||
|
||||
// errNotObject is returned when an object implements the List style interfaces but not the Object style
|
||||
// interfaces.
|
||||
var errNotObject = fmt.Errorf("object does not implement the Object interfaces")
|
||||
|
||||
// Accessor takes an arbitrary object pointer and returns meta.Interface.
|
||||
// obj must be a pointer to an API type. An error is returned if the minimum
|
||||
// required fields are missing. Fields that are not required return the default
|
||||
// value and are a no-op if set.
|
||||
// TODO: return bool instead of error
|
||||
func Accessor(obj interface{}) (metav1.Object, error) {
|
||||
switch t := obj.(type) {
|
||||
case metav1.Object:
|
||||
return t, nil
|
||||
case metav1.ObjectMetaAccessor:
|
||||
if m := t.GetObjectMeta(); m != nil {
|
||||
return m, nil
|
||||
}
|
||||
return nil, errNotObject
|
||||
default:
|
||||
return nil, errNotObject
|
||||
}
|
||||
}
|
||||
|
||||
// AsPartialObjectMetadata takes the metav1 interface and returns a partial object.
|
||||
// TODO: consider making this solely a conversion action.
|
||||
func AsPartialObjectMetadata(m metav1.Object) *metav1alpha1.PartialObjectMetadata {
|
||||
switch t := m.(type) {
|
||||
case *metav1.ObjectMeta:
|
||||
return &metav1alpha1.PartialObjectMetadata{ObjectMeta: *t}
|
||||
default:
|
||||
return &metav1alpha1.PartialObjectMetadata{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: m.GetName(),
|
||||
GenerateName: m.GetGenerateName(),
|
||||
Namespace: m.GetNamespace(),
|
||||
SelfLink: m.GetSelfLink(),
|
||||
UID: m.GetUID(),
|
||||
ResourceVersion: m.GetResourceVersion(),
|
||||
Generation: m.GetGeneration(),
|
||||
CreationTimestamp: m.GetCreationTimestamp(),
|
||||
DeletionTimestamp: m.GetDeletionTimestamp(),
|
||||
DeletionGracePeriodSeconds: m.GetDeletionGracePeriodSeconds(),
|
||||
Labels: m.GetLabels(),
|
||||
Annotations: m.GetAnnotations(),
|
||||
OwnerReferences: m.GetOwnerReferences(),
|
||||
Finalizers: m.GetFinalizers(),
|
||||
ClusterName: m.GetClusterName(),
|
||||
Initializers: m.GetInitializers(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TypeAccessor returns an interface that allows retrieving and modifying the APIVersion
|
||||
// and Kind of an in-memory internal object.
|
||||
// TODO: this interface is used to test code that does not have ObjectMeta or ListMeta
|
||||
// in round tripping (objects which can use apiVersion/kind, but do not fit the Kube
|
||||
// api conventions).
|
||||
func TypeAccessor(obj interface{}) (Type, error) {
|
||||
if typed, ok := obj.(runtime.Object); ok {
|
||||
return objectAccessor{typed}, nil
|
||||
}
|
||||
v, err := conversion.EnforcePtr(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t := v.Type()
|
||||
if v.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), t, v.Interface())
|
||||
}
|
||||
|
||||
typeMeta := v.FieldByName("TypeMeta")
|
||||
if !typeMeta.IsValid() {
|
||||
return nil, fmt.Errorf("struct %v lacks embedded TypeMeta type", t)
|
||||
}
|
||||
a := &genericAccessor{}
|
||||
if err := extractFromTypeMeta(typeMeta, a); err != nil {
|
||||
return nil, fmt.Errorf("unable to find type fields on %#v: %v", typeMeta, err)
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
type objectAccessor struct {
|
||||
runtime.Object
|
||||
}
|
||||
|
||||
func (obj objectAccessor) GetKind() string {
|
||||
return obj.GetObjectKind().GroupVersionKind().Kind
|
||||
}
|
||||
|
||||
func (obj objectAccessor) SetKind(kind string) {
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
gvk.Kind = kind
|
||||
obj.GetObjectKind().SetGroupVersionKind(gvk)
|
||||
}
|
||||
|
||||
func (obj objectAccessor) GetAPIVersion() string {
|
||||
return obj.GetObjectKind().GroupVersionKind().GroupVersion().String()
|
||||
}
|
||||
|
||||
func (obj objectAccessor) SetAPIVersion(version string) {
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
gv, err := schema.ParseGroupVersion(version)
|
||||
if err != nil {
|
||||
gv = schema.GroupVersion{Version: version}
|
||||
}
|
||||
gvk.Group, gvk.Version = gv.Group, gv.Version
|
||||
obj.GetObjectKind().SetGroupVersionKind(gvk)
|
||||
}
|
||||
|
||||
// NewAccessor returns a MetadataAccessor that can retrieve
|
||||
// or manipulate resource version on objects derived from core API
|
||||
// metadata concepts.
|
||||
func NewAccessor() MetadataAccessor {
|
||||
return resourceAccessor{}
|
||||
}
|
||||
|
||||
// resourceAccessor implements ResourceVersioner and SelfLinker.
|
||||
type resourceAccessor struct{}
|
||||
|
||||
func (resourceAccessor) Kind(obj runtime.Object) (string, error) {
|
||||
return objectAccessor{obj}.GetKind(), nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) SetKind(obj runtime.Object, kind string) error {
|
||||
objectAccessor{obj}.SetKind(kind)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) APIVersion(obj runtime.Object) (string, error) {
|
||||
return objectAccessor{obj}.GetAPIVersion(), nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) SetAPIVersion(obj runtime.Object, version string) error {
|
||||
objectAccessor{obj}.SetAPIVersion(version)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) Namespace(obj runtime.Object) (string, error) {
|
||||
accessor, err := Accessor(obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return accessor.GetNamespace(), nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) SetNamespace(obj runtime.Object, namespace string) error {
|
||||
accessor, err := Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
accessor.SetNamespace(namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) Name(obj runtime.Object) (string, error) {
|
||||
accessor, err := Accessor(obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return accessor.GetName(), nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) SetName(obj runtime.Object, name string) error {
|
||||
accessor, err := Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
accessor.SetName(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) GenerateName(obj runtime.Object) (string, error) {
|
||||
accessor, err := Accessor(obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return accessor.GetGenerateName(), nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) SetGenerateName(obj runtime.Object, name string) error {
|
||||
accessor, err := Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
accessor.SetGenerateName(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) UID(obj runtime.Object) (types.UID, error) {
|
||||
accessor, err := Accessor(obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return accessor.GetUID(), nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) SetUID(obj runtime.Object, uid types.UID) error {
|
||||
accessor, err := Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
accessor.SetUID(uid)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) SelfLink(obj runtime.Object) (string, error) {
|
||||
accessor, err := CommonAccessor(obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return accessor.GetSelfLink(), nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) SetSelfLink(obj runtime.Object, selfLink string) error {
|
||||
accessor, err := CommonAccessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
accessor.SetSelfLink(selfLink)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) Labels(obj runtime.Object) (map[string]string, error) {
|
||||
accessor, err := Accessor(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return accessor.GetLabels(), nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) SetLabels(obj runtime.Object, labels map[string]string) error {
|
||||
accessor, err := Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
accessor.SetLabels(labels)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) Annotations(obj runtime.Object) (map[string]string, error) {
|
||||
accessor, err := Accessor(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return accessor.GetAnnotations(), nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) SetAnnotations(obj runtime.Object, annotations map[string]string) error {
|
||||
accessor, err := Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
accessor.SetAnnotations(annotations)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) ResourceVersion(obj runtime.Object) (string, error) {
|
||||
accessor, err := CommonAccessor(obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return accessor.GetResourceVersion(), nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) SetResourceVersion(obj runtime.Object, version string) error {
|
||||
accessor, err := CommonAccessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
accessor.SetResourceVersion(version)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) Continue(obj runtime.Object) (string, error) {
|
||||
accessor, err := ListAccessor(obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return accessor.GetContinue(), nil
|
||||
}
|
||||
|
||||
func (resourceAccessor) SetContinue(obj runtime.Object, version string) error {
|
||||
accessor, err := ListAccessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
accessor.SetContinue(version)
|
||||
return nil
|
||||
}
|
||||
|
||||
// extractFromOwnerReference extracts v to o. v is the OwnerReferences field of an object.
|
||||
func extractFromOwnerReference(v reflect.Value, o *metav1.OwnerReference) error {
|
||||
if err := runtime.Field(v, "APIVersion", &o.APIVersion); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := runtime.Field(v, "Kind", &o.Kind); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := runtime.Field(v, "Name", &o.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := runtime.Field(v, "UID", &o.UID); err != nil {
|
||||
return err
|
||||
}
|
||||
var controllerPtr *bool
|
||||
if err := runtime.Field(v, "Controller", &controllerPtr); err != nil {
|
||||
return err
|
||||
}
|
||||
if controllerPtr != nil {
|
||||
controller := *controllerPtr
|
||||
o.Controller = &controller
|
||||
}
|
||||
var blockOwnerDeletionPtr *bool
|
||||
if err := runtime.Field(v, "BlockOwnerDeletion", &blockOwnerDeletionPtr); err != nil {
|
||||
return err
|
||||
}
|
||||
if blockOwnerDeletionPtr != nil {
|
||||
block := *blockOwnerDeletionPtr
|
||||
o.BlockOwnerDeletion = &block
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setOwnerReference sets v to o. v is the OwnerReferences field of an object.
|
||||
func setOwnerReference(v reflect.Value, o *metav1.OwnerReference) error {
|
||||
if err := runtime.SetField(o.APIVersion, v, "APIVersion"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := runtime.SetField(o.Kind, v, "Kind"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := runtime.SetField(o.Name, v, "Name"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := runtime.SetField(o.UID, v, "UID"); err != nil {
|
||||
return err
|
||||
}
|
||||
if o.Controller != nil {
|
||||
controller := *(o.Controller)
|
||||
if err := runtime.SetField(&controller, v, "Controller"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if o.BlockOwnerDeletion != nil {
|
||||
block := *(o.BlockOwnerDeletion)
|
||||
if err := runtime.SetField(&block, v, "BlockOwnerDeletion"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// genericAccessor contains pointers to strings that can modify an arbitrary
|
||||
// struct and implements the Accessor interface.
|
||||
type genericAccessor struct {
|
||||
namespace *string
|
||||
name *string
|
||||
generateName *string
|
||||
uid *types.UID
|
||||
apiVersion *string
|
||||
kind *string
|
||||
resourceVersion *string
|
||||
selfLink *string
|
||||
creationTimestamp *metav1.Time
|
||||
deletionTimestamp **metav1.Time
|
||||
labels *map[string]string
|
||||
annotations *map[string]string
|
||||
ownerReferences reflect.Value
|
||||
finalizers *[]string
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetNamespace() string {
|
||||
if a.namespace == nil {
|
||||
return ""
|
||||
}
|
||||
return *a.namespace
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetNamespace(namespace string) {
|
||||
if a.namespace == nil {
|
||||
return
|
||||
}
|
||||
*a.namespace = namespace
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetName() string {
|
||||
if a.name == nil {
|
||||
return ""
|
||||
}
|
||||
return *a.name
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetName(name string) {
|
||||
if a.name == nil {
|
||||
return
|
||||
}
|
||||
*a.name = name
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetGenerateName() string {
|
||||
if a.generateName == nil {
|
||||
return ""
|
||||
}
|
||||
return *a.generateName
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetGenerateName(generateName string) {
|
||||
if a.generateName == nil {
|
||||
return
|
||||
}
|
||||
*a.generateName = generateName
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetUID() types.UID {
|
||||
if a.uid == nil {
|
||||
return ""
|
||||
}
|
||||
return *a.uid
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetUID(uid types.UID) {
|
||||
if a.uid == nil {
|
||||
return
|
||||
}
|
||||
*a.uid = uid
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetAPIVersion() string {
|
||||
return *a.apiVersion
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetAPIVersion(version string) {
|
||||
*a.apiVersion = version
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetKind() string {
|
||||
return *a.kind
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetKind(kind string) {
|
||||
*a.kind = kind
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetResourceVersion() string {
|
||||
return *a.resourceVersion
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetResourceVersion(version string) {
|
||||
*a.resourceVersion = version
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetSelfLink() string {
|
||||
return *a.selfLink
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetSelfLink(selfLink string) {
|
||||
*a.selfLink = selfLink
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetCreationTimestamp() metav1.Time {
|
||||
return *a.creationTimestamp
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetCreationTimestamp(timestamp metav1.Time) {
|
||||
*a.creationTimestamp = timestamp
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetDeletionTimestamp() *metav1.Time {
|
||||
return *a.deletionTimestamp
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetDeletionTimestamp(timestamp *metav1.Time) {
|
||||
*a.deletionTimestamp = timestamp
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetLabels() map[string]string {
|
||||
if a.labels == nil {
|
||||
return nil
|
||||
}
|
||||
return *a.labels
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetLabels(labels map[string]string) {
|
||||
*a.labels = labels
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetAnnotations() map[string]string {
|
||||
if a.annotations == nil {
|
||||
return nil
|
||||
}
|
||||
return *a.annotations
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetAnnotations(annotations map[string]string) {
|
||||
if a.annotations == nil {
|
||||
emptyAnnotations := make(map[string]string)
|
||||
a.annotations = &emptyAnnotations
|
||||
}
|
||||
*a.annotations = annotations
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetFinalizers() []string {
|
||||
if a.finalizers == nil {
|
||||
return nil
|
||||
}
|
||||
return *a.finalizers
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetFinalizers(finalizers []string) {
|
||||
*a.finalizers = finalizers
|
||||
}
|
||||
|
||||
func (a genericAccessor) GetOwnerReferences() []metav1.OwnerReference {
|
||||
var ret []metav1.OwnerReference
|
||||
s := a.ownerReferences
|
||||
if s.Kind() != reflect.Ptr || s.Elem().Kind() != reflect.Slice {
|
||||
glog.Errorf("expect %v to be a pointer to slice", s)
|
||||
return ret
|
||||
}
|
||||
s = s.Elem()
|
||||
// Set the capacity to one element greater to avoid copy if the caller later append an element.
|
||||
ret = make([]metav1.OwnerReference, s.Len(), s.Len()+1)
|
||||
for i := 0; i < s.Len(); i++ {
|
||||
if err := extractFromOwnerReference(s.Index(i), &ret[i]); err != nil {
|
||||
glog.Errorf("extractFromOwnerReference failed: %v", err)
|
||||
return ret
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (a genericAccessor) SetOwnerReferences(references []metav1.OwnerReference) {
|
||||
s := a.ownerReferences
|
||||
if s.Kind() != reflect.Ptr || s.Elem().Kind() != reflect.Slice {
|
||||
glog.Errorf("expect %v to be a pointer to slice", s)
|
||||
}
|
||||
s = s.Elem()
|
||||
newReferences := reflect.MakeSlice(s.Type(), len(references), len(references))
|
||||
for i := 0; i < len(references); i++ {
|
||||
if err := setOwnerReference(newReferences.Index(i), &references[i]); err != nil {
|
||||
glog.Errorf("setOwnerReference failed: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
s.Set(newReferences)
|
||||
}
|
||||
|
||||
// extractFromTypeMeta extracts pointers to version and kind fields from an object
|
||||
func extractFromTypeMeta(v reflect.Value, a *genericAccessor) error {
|
||||
if err := runtime.FieldPtr(v, "APIVersion", &a.apiVersion); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := runtime.FieldPtr(v, "Kind", &a.kind); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
51
vendor/k8s.io/apimachinery/pkg/api/meta/meta_test.go
generated
vendored
Normal file
51
vendor/k8s.io/apimachinery/pkg/api/meta/meta_test.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright 2017 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 meta
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1alpha1 "k8s.io/apimachinery/pkg/apis/meta/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
|
||||
fuzz "github.com/google/gofuzz"
|
||||
)
|
||||
|
||||
func TestAsPartialObjectMetadata(t *testing.T) {
|
||||
f := fuzz.New().NilChance(.5).NumElements(0, 1).RandSource(rand.NewSource(1))
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
m := &metav1.ObjectMeta{}
|
||||
f.Fuzz(m)
|
||||
partial := AsPartialObjectMetadata(m)
|
||||
if !reflect.DeepEqual(&partial.ObjectMeta, m) {
|
||||
t.Fatalf("incomplete partial object metadata: %s", diff.ObjectReflectDiff(&partial.ObjectMeta, m))
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
m := &metav1alpha1.PartialObjectMetadata{}
|
||||
f.Fuzz(&m.ObjectMeta)
|
||||
partial := AsPartialObjectMetadata(m)
|
||||
if !reflect.DeepEqual(&partial.ObjectMeta, &m.ObjectMeta) {
|
||||
t.Fatalf("incomplete partial object metadata: %s", diff.ObjectReflectDiff(&partial.ObjectMeta, &m.ObjectMeta))
|
||||
}
|
||||
}
|
||||
}
|
210
vendor/k8s.io/apimachinery/pkg/api/meta/multirestmapper.go
generated
vendored
Normal file
210
vendor/k8s.io/apimachinery/pkg/api/meta/multirestmapper.go
generated
vendored
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
Copyright 2014 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 meta
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
)
|
||||
|
||||
// MultiRESTMapper is a wrapper for multiple RESTMappers.
|
||||
type MultiRESTMapper []RESTMapper
|
||||
|
||||
func (m MultiRESTMapper) String() string {
|
||||
nested := []string{}
|
||||
for _, t := range m {
|
||||
currString := fmt.Sprintf("%v", t)
|
||||
splitStrings := strings.Split(currString, "\n")
|
||||
nested = append(nested, strings.Join(splitStrings, "\n\t"))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("MultiRESTMapper{\n\t%s\n}", strings.Join(nested, "\n\t"))
|
||||
}
|
||||
|
||||
// ResourceSingularizer converts a REST resource name from plural to singular (e.g., from pods to pod)
|
||||
// This implementation supports multiple REST schemas and return the first match.
|
||||
func (m MultiRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
|
||||
for _, t := range m {
|
||||
singular, err = t.ResourceSingularizer(resource)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (m MultiRESTMapper) ResourcesFor(resource schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
|
||||
allGVRs := []schema.GroupVersionResource{}
|
||||
for _, t := range m {
|
||||
gvrs, err := t.ResourcesFor(resource)
|
||||
// ignore "no match" errors, but any other error percolates back up
|
||||
if IsNoMatchError(err) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// walk the existing values to de-dup
|
||||
for _, curr := range gvrs {
|
||||
found := false
|
||||
for _, existing := range allGVRs {
|
||||
if curr == existing {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
allGVRs = append(allGVRs, curr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(allGVRs) == 0 {
|
||||
return nil, &NoResourceMatchError{PartialResource: resource}
|
||||
}
|
||||
|
||||
return allGVRs, nil
|
||||
}
|
||||
|
||||
func (m MultiRESTMapper) KindsFor(resource schema.GroupVersionResource) (gvk []schema.GroupVersionKind, err error) {
|
||||
allGVKs := []schema.GroupVersionKind{}
|
||||
for _, t := range m {
|
||||
gvks, err := t.KindsFor(resource)
|
||||
// ignore "no match" errors, but any other error percolates back up
|
||||
if IsNoMatchError(err) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// walk the existing values to de-dup
|
||||
for _, curr := range gvks {
|
||||
found := false
|
||||
for _, existing := range allGVKs {
|
||||
if curr == existing {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
allGVKs = append(allGVKs, curr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(allGVKs) == 0 {
|
||||
return nil, &NoResourceMatchError{PartialResource: resource}
|
||||
}
|
||||
|
||||
return allGVKs, nil
|
||||
}
|
||||
|
||||
func (m MultiRESTMapper) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
|
||||
resources, err := m.ResourcesFor(resource)
|
||||
if err != nil {
|
||||
return schema.GroupVersionResource{}, err
|
||||
}
|
||||
if len(resources) == 1 {
|
||||
return resources[0], nil
|
||||
}
|
||||
|
||||
return schema.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: resource, MatchingResources: resources}
|
||||
}
|
||||
|
||||
func (m MultiRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||
kinds, err := m.KindsFor(resource)
|
||||
if err != nil {
|
||||
return schema.GroupVersionKind{}, err
|
||||
}
|
||||
if len(kinds) == 1 {
|
||||
return kinds[0], nil
|
||||
}
|
||||
|
||||
return schema.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: resource, MatchingKinds: kinds}
|
||||
}
|
||||
|
||||
// RESTMapping provides the REST mapping for the resource based on the
|
||||
// kind and version. This implementation supports multiple REST schemas and
|
||||
// return the first match.
|
||||
func (m MultiRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error) {
|
||||
allMappings := []*RESTMapping{}
|
||||
errors := []error{}
|
||||
|
||||
for _, t := range m {
|
||||
currMapping, err := t.RESTMapping(gk, versions...)
|
||||
// ignore "no match" errors, but any other error percolates back up
|
||||
if IsNoMatchError(err) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
errors = append(errors, err)
|
||||
continue
|
||||
}
|
||||
|
||||
allMappings = append(allMappings, currMapping)
|
||||
}
|
||||
|
||||
// if we got exactly one mapping, then use it even if other requested failed
|
||||
if len(allMappings) == 1 {
|
||||
return allMappings[0], nil
|
||||
}
|
||||
if len(allMappings) > 1 {
|
||||
var kinds []schema.GroupVersionKind
|
||||
for _, m := range allMappings {
|
||||
kinds = append(kinds, m.GroupVersionKind)
|
||||
}
|
||||
return nil, &AmbiguousKindError{PartialKind: gk.WithVersion(""), MatchingKinds: kinds}
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
return nil, utilerrors.NewAggregate(errors)
|
||||
}
|
||||
return nil, &NoKindMatchError{PartialKind: gk.WithVersion("")}
|
||||
}
|
||||
|
||||
// RESTMappings returns all possible RESTMappings for the provided group kind, or an error
|
||||
// if the type is not recognized.
|
||||
func (m MultiRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error) {
|
||||
var allMappings []*RESTMapping
|
||||
var errors []error
|
||||
|
||||
for _, t := range m {
|
||||
currMappings, err := t.RESTMappings(gk, versions...)
|
||||
// ignore "no match" errors, but any other error percolates back up
|
||||
if IsNoMatchError(err) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
errors = append(errors, err)
|
||||
continue
|
||||
}
|
||||
allMappings = append(allMappings, currMappings...)
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
return nil, utilerrors.NewAggregate(errors)
|
||||
}
|
||||
if len(allMappings) == 0 {
|
||||
return nil, &NoKindMatchError{PartialKind: gk.WithVersion("")}
|
||||
}
|
||||
return allMappings, nil
|
||||
}
|
355
vendor/k8s.io/apimachinery/pkg/api/meta/multirestmapper_test.go
generated
vendored
Normal file
355
vendor/k8s.io/apimachinery/pkg/api/meta/multirestmapper_test.go
generated
vendored
Normal file
@ -0,0 +1,355 @@
|
||||
/*
|
||||
Copyright 2014 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 meta
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func TestMultiRESTMapperResourceFor(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
mapper MultiRESTMapper
|
||||
input schema.GroupVersionResource
|
||||
result schema.GroupVersionResource
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
mapper: MultiRESTMapper{},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: schema.GroupVersionResource{},
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "ignore not found",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: schema.GroupVersionResource{},
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "accept first failure",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "unused"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: schema.GroupVersionResource{},
|
||||
err: errors.New("fail on this"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
actualResult, actualErr := tc.mapper.ResourceFor(tc.input)
|
||||
if e, a := tc.result, actualResult; e != a {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
switch {
|
||||
case tc.err == nil && actualErr == nil:
|
||||
case tc.err == nil:
|
||||
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
|
||||
case actualErr == nil:
|
||||
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
|
||||
case tc.err.Error() != actualErr.Error():
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiRESTMapperResourcesFor(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
mapper MultiRESTMapper
|
||||
input schema.GroupVersionResource
|
||||
result []schema.GroupVersionResource
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
mapper: MultiRESTMapper{},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: nil,
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "ignore not found",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: nil,
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "accept first failure",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "unused"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: nil,
|
||||
err: errors.New("fail on this"),
|
||||
},
|
||||
{
|
||||
name: "union and dedup",
|
||||
mapper: MultiRESTMapper{
|
||||
fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "dupe"}, {Resource: "first"}}},
|
||||
fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "dupe"}, {Resource: "second"}}},
|
||||
},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: []schema.GroupVersionResource{{Resource: "dupe"}, {Resource: "first"}, {Resource: "second"}},
|
||||
},
|
||||
{
|
||||
name: "skip not and continue",
|
||||
mapper: MultiRESTMapper{
|
||||
fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}},
|
||||
fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "first"}, {Resource: "second"}}},
|
||||
},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: []schema.GroupVersionResource{{Resource: "first"}, {Resource: "second"}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
actualResult, actualErr := tc.mapper.ResourcesFor(tc.input)
|
||||
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
switch {
|
||||
case tc.err == nil && actualErr == nil:
|
||||
case tc.err == nil:
|
||||
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
|
||||
case actualErr == nil:
|
||||
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
|
||||
case tc.err.Error() != actualErr.Error():
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiRESTMapperKindsFor(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
mapper MultiRESTMapper
|
||||
input schema.GroupVersionResource
|
||||
result []schema.GroupVersionKind
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
mapper: MultiRESTMapper{},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: nil,
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "ignore not found",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: nil,
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "accept first failure",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "unused"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: nil,
|
||||
err: errors.New("fail on this"),
|
||||
},
|
||||
{
|
||||
name: "union and dedup",
|
||||
mapper: MultiRESTMapper{
|
||||
fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "dupe"}, {Kind: "first"}}},
|
||||
fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "dupe"}, {Kind: "second"}}},
|
||||
},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: []schema.GroupVersionKind{{Kind: "dupe"}, {Kind: "first"}, {Kind: "second"}},
|
||||
},
|
||||
{
|
||||
name: "skip not and continue",
|
||||
mapper: MultiRESTMapper{
|
||||
fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}},
|
||||
fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "first"}, {Kind: "second"}}},
|
||||
},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: []schema.GroupVersionKind{{Kind: "first"}, {Kind: "second"}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
actualResult, actualErr := tc.mapper.KindsFor(tc.input)
|
||||
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
switch {
|
||||
case tc.err == nil && actualErr == nil:
|
||||
case tc.err == nil:
|
||||
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
|
||||
case actualErr == nil:
|
||||
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
|
||||
case tc.err.Error() != actualErr.Error():
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiRESTMapperKindFor(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
mapper MultiRESTMapper
|
||||
input schema.GroupVersionResource
|
||||
result schema.GroupVersionKind
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
mapper: MultiRESTMapper{},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: schema.GroupVersionKind{},
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "ignore not found",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: schema.GroupVersionKind{},
|
||||
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "accept first failure",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "unused"}}}},
|
||||
input: schema.GroupVersionResource{Resource: "foo"},
|
||||
result: schema.GroupVersionKind{},
|
||||
err: errors.New("fail on this"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
actualResult, actualErr := tc.mapper.KindFor(tc.input)
|
||||
if e, a := tc.result, actualResult; e != a {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
switch {
|
||||
case tc.err == nil && actualErr == nil:
|
||||
case tc.err == nil:
|
||||
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
|
||||
case actualErr == nil:
|
||||
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
|
||||
case tc.err.Error() != actualErr.Error():
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiRESTMapperRESTMappings(t *testing.T) {
|
||||
mapping1, mapping2 := &RESTMapping{}, &RESTMapping{}
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
mapper MultiRESTMapper
|
||||
input schema.GroupKind
|
||||
result []*RESTMapping
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
mapper: MultiRESTMapper{},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: nil,
|
||||
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}},
|
||||
},
|
||||
{
|
||||
name: "ignore not found",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "IGNORE_THIS"}}}},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: nil,
|
||||
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}},
|
||||
},
|
||||
{
|
||||
name: "accept first failure",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{mappings: []*RESTMapping{mapping1}}},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: nil,
|
||||
err: errors.New("fail on this"),
|
||||
},
|
||||
{
|
||||
name: "return both",
|
||||
mapper: MultiRESTMapper{fixedRESTMapper{mappings: []*RESTMapping{mapping1}}, fixedRESTMapper{mappings: []*RESTMapping{mapping2}}},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: []*RESTMapping{mapping1, mapping2},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
actualResult, actualErr := tc.mapper.RESTMappings(tc.input)
|
||||
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
switch {
|
||||
case tc.err == nil && actualErr == nil:
|
||||
case tc.err == nil:
|
||||
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
|
||||
case actualErr == nil:
|
||||
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
|
||||
case tc.err.Error() != actualErr.Error():
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type fixedRESTMapper struct {
|
||||
resourcesFor []schema.GroupVersionResource
|
||||
kindsFor []schema.GroupVersionKind
|
||||
resourceFor schema.GroupVersionResource
|
||||
kindFor schema.GroupVersionKind
|
||||
mappings []*RESTMapping
|
||||
|
||||
err error
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
|
||||
return "", m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) ResourcesFor(resource schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
|
||||
return m.resourcesFor, m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) KindsFor(resource schema.GroupVersionResource) (gvk []schema.GroupVersionKind, err error) {
|
||||
return m.kindsFor, m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
|
||||
return m.resourceFor, m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||
return m.kindFor, m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (mapping *RESTMapping, err error) {
|
||||
return nil, m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) (mappings []*RESTMapping, err error) {
|
||||
return m.mappings, m.err
|
||||
}
|
||||
|
||||
func (m fixedRESTMapper) ResourceIsValid(resource schema.GroupVersionResource) bool {
|
||||
return false
|
||||
}
|
222
vendor/k8s.io/apimachinery/pkg/api/meta/priority.go
generated
vendored
Normal file
222
vendor/k8s.io/apimachinery/pkg/api/meta/priority.go
generated
vendored
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
Copyright 2016 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 meta
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
AnyGroup = "*"
|
||||
AnyVersion = "*"
|
||||
AnyResource = "*"
|
||||
AnyKind = "*"
|
||||
)
|
||||
|
||||
// PriorityRESTMapper is a wrapper for automatically choosing a particular Resource or Kind
|
||||
// when multiple matches are possible
|
||||
type PriorityRESTMapper struct {
|
||||
// Delegate is the RESTMapper to use to locate all the Kind and Resource matches
|
||||
Delegate RESTMapper
|
||||
|
||||
// ResourcePriority is a list of priority patterns to apply to matching resources.
|
||||
// The list of all matching resources is narrowed based on the patterns until only one remains.
|
||||
// A pattern with no matches is skipped. A pattern with more than one match uses its
|
||||
// matches as the list to continue matching against.
|
||||
ResourcePriority []schema.GroupVersionResource
|
||||
|
||||
// KindPriority is a list of priority patterns to apply to matching kinds.
|
||||
// The list of all matching kinds is narrowed based on the patterns until only one remains.
|
||||
// A pattern with no matches is skipped. A pattern with more than one match uses its
|
||||
// matches as the list to continue matching against.
|
||||
KindPriority []schema.GroupVersionKind
|
||||
}
|
||||
|
||||
func (m PriorityRESTMapper) String() string {
|
||||
return fmt.Sprintf("PriorityRESTMapper{\n\t%v\n\t%v\n\t%v\n}", m.ResourcePriority, m.KindPriority, m.Delegate)
|
||||
}
|
||||
|
||||
// ResourceFor finds all resources, then passes them through the ResourcePriority patterns to find a single matching hit.
|
||||
func (m PriorityRESTMapper) ResourceFor(partiallySpecifiedResource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
|
||||
originalGVRs, err := m.Delegate.ResourcesFor(partiallySpecifiedResource)
|
||||
if err != nil {
|
||||
return schema.GroupVersionResource{}, err
|
||||
}
|
||||
if len(originalGVRs) == 1 {
|
||||
return originalGVRs[0], nil
|
||||
}
|
||||
|
||||
remainingGVRs := append([]schema.GroupVersionResource{}, originalGVRs...)
|
||||
for _, pattern := range m.ResourcePriority {
|
||||
matchedGVRs := []schema.GroupVersionResource{}
|
||||
for _, gvr := range remainingGVRs {
|
||||
if resourceMatches(pattern, gvr) {
|
||||
matchedGVRs = append(matchedGVRs, gvr)
|
||||
}
|
||||
}
|
||||
|
||||
switch len(matchedGVRs) {
|
||||
case 0:
|
||||
// if you have no matches, then nothing matched this pattern just move to the next
|
||||
continue
|
||||
case 1:
|
||||
// one match, return
|
||||
return matchedGVRs[0], nil
|
||||
default:
|
||||
// more than one match, use the matched hits as the list moving to the next pattern.
|
||||
// this way you can have a series of selection criteria
|
||||
remainingGVRs = matchedGVRs
|
||||
}
|
||||
}
|
||||
|
||||
return schema.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: partiallySpecifiedResource, MatchingResources: originalGVRs}
|
||||
}
|
||||
|
||||
// KindFor finds all kinds, then passes them through the KindPriority patterns to find a single matching hit.
|
||||
func (m PriorityRESTMapper) KindFor(partiallySpecifiedResource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||
originalGVKs, err := m.Delegate.KindsFor(partiallySpecifiedResource)
|
||||
if err != nil {
|
||||
return schema.GroupVersionKind{}, err
|
||||
}
|
||||
if len(originalGVKs) == 1 {
|
||||
return originalGVKs[0], nil
|
||||
}
|
||||
|
||||
remainingGVKs := append([]schema.GroupVersionKind{}, originalGVKs...)
|
||||
for _, pattern := range m.KindPriority {
|
||||
matchedGVKs := []schema.GroupVersionKind{}
|
||||
for _, gvr := range remainingGVKs {
|
||||
if kindMatches(pattern, gvr) {
|
||||
matchedGVKs = append(matchedGVKs, gvr)
|
||||
}
|
||||
}
|
||||
|
||||
switch len(matchedGVKs) {
|
||||
case 0:
|
||||
// if you have no matches, then nothing matched this pattern just move to the next
|
||||
continue
|
||||
case 1:
|
||||
// one match, return
|
||||
return matchedGVKs[0], nil
|
||||
default:
|
||||
// more than one match, use the matched hits as the list moving to the next pattern.
|
||||
// this way you can have a series of selection criteria
|
||||
remainingGVKs = matchedGVKs
|
||||
}
|
||||
}
|
||||
|
||||
return schema.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: partiallySpecifiedResource, MatchingKinds: originalGVKs}
|
||||
}
|
||||
|
||||
func resourceMatches(pattern schema.GroupVersionResource, resource schema.GroupVersionResource) bool {
|
||||
if pattern.Group != AnyGroup && pattern.Group != resource.Group {
|
||||
return false
|
||||
}
|
||||
if pattern.Version != AnyVersion && pattern.Version != resource.Version {
|
||||
return false
|
||||
}
|
||||
if pattern.Resource != AnyResource && pattern.Resource != resource.Resource {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func kindMatches(pattern schema.GroupVersionKind, kind schema.GroupVersionKind) bool {
|
||||
if pattern.Group != AnyGroup && pattern.Group != kind.Group {
|
||||
return false
|
||||
}
|
||||
if pattern.Version != AnyVersion && pattern.Version != kind.Version {
|
||||
return false
|
||||
}
|
||||
if pattern.Kind != AnyKind && pattern.Kind != kind.Kind {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (m PriorityRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (mapping *RESTMapping, err error) {
|
||||
mappings, err := m.Delegate.RESTMappings(gk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// any versions the user provides take priority
|
||||
priorities := m.KindPriority
|
||||
if len(versions) > 0 {
|
||||
priorities = make([]schema.GroupVersionKind, 0, len(m.KindPriority)+len(versions))
|
||||
for _, version := range versions {
|
||||
gv := schema.GroupVersion{
|
||||
Version: version,
|
||||
Group: gk.Group,
|
||||
}
|
||||
priorities = append(priorities, gv.WithKind(AnyKind))
|
||||
}
|
||||
priorities = append(priorities, m.KindPriority...)
|
||||
}
|
||||
|
||||
remaining := append([]*RESTMapping{}, mappings...)
|
||||
for _, pattern := range priorities {
|
||||
var matching []*RESTMapping
|
||||
for _, m := range remaining {
|
||||
if kindMatches(pattern, m.GroupVersionKind) {
|
||||
matching = append(matching, m)
|
||||
}
|
||||
}
|
||||
|
||||
switch len(matching) {
|
||||
case 0:
|
||||
// if you have no matches, then nothing matched this pattern just move to the next
|
||||
continue
|
||||
case 1:
|
||||
// one match, return
|
||||
return matching[0], nil
|
||||
default:
|
||||
// more than one match, use the matched hits as the list moving to the next pattern.
|
||||
// this way you can have a series of selection criteria
|
||||
remaining = matching
|
||||
}
|
||||
}
|
||||
if len(remaining) == 1 {
|
||||
return remaining[0], nil
|
||||
}
|
||||
|
||||
var kinds []schema.GroupVersionKind
|
||||
for _, m := range mappings {
|
||||
kinds = append(kinds, m.GroupVersionKind)
|
||||
}
|
||||
return nil, &AmbiguousKindError{PartialKind: gk.WithVersion(""), MatchingKinds: kinds}
|
||||
}
|
||||
|
||||
func (m PriorityRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error) {
|
||||
return m.Delegate.RESTMappings(gk, versions...)
|
||||
}
|
||||
|
||||
func (m PriorityRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
|
||||
return m.Delegate.ResourceSingularizer(resource)
|
||||
}
|
||||
|
||||
func (m PriorityRESTMapper) ResourcesFor(partiallySpecifiedResource schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
|
||||
return m.Delegate.ResourcesFor(partiallySpecifiedResource)
|
||||
}
|
||||
|
||||
func (m PriorityRESTMapper) KindsFor(partiallySpecifiedResource schema.GroupVersionResource) (gvk []schema.GroupVersionKind, err error) {
|
||||
return m.Delegate.KindsFor(partiallySpecifiedResource)
|
||||
}
|
346
vendor/k8s.io/apimachinery/pkg/api/meta/priority_test.go
generated
vendored
Normal file
346
vendor/k8s.io/apimachinery/pkg/api/meta/priority_test.go
generated
vendored
Normal file
@ -0,0 +1,346 @@
|
||||
/*
|
||||
Copyright 2016 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 meta
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func TestPriorityRESTMapperResourceForErrorHandling(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
delegate RESTMapper
|
||||
resourcePatterns []schema.GroupVersionResource
|
||||
result schema.GroupVersionResource
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "single hit",
|
||||
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "single-hit"}}},
|
||||
result: schema.GroupVersionResource{Resource: "single-hit"},
|
||||
},
|
||||
{
|
||||
name: "ambiguous match",
|
||||
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: "a", Resource: "first"},
|
||||
{Group: "two", Version: "b", Resource: "second"},
|
||||
}},
|
||||
err: "matches multiple resources",
|
||||
},
|
||||
{
|
||||
name: "group selection",
|
||||
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: "a", Resource: "first"},
|
||||
{Group: "two", Version: "b", Resource: "second"},
|
||||
}},
|
||||
resourcePatterns: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: AnyVersion, Resource: AnyResource},
|
||||
},
|
||||
result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"},
|
||||
},
|
||||
{
|
||||
name: "empty match continues",
|
||||
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: "a", Resource: "first"},
|
||||
{Group: "two", Version: "b", Resource: "second"},
|
||||
}},
|
||||
resourcePatterns: []schema.GroupVersionResource{
|
||||
{Group: "fail", Version: AnyVersion, Resource: AnyResource},
|
||||
{Group: "one", Version: AnyVersion, Resource: AnyResource},
|
||||
},
|
||||
result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"},
|
||||
},
|
||||
{
|
||||
name: "group followed by version selection",
|
||||
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: "a", Resource: "first"},
|
||||
{Group: "two", Version: "b", Resource: "second"},
|
||||
{Group: "one", Version: "c", Resource: "third"},
|
||||
}},
|
||||
resourcePatterns: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: AnyVersion, Resource: AnyResource},
|
||||
{Group: AnyGroup, Version: "a", Resource: AnyResource},
|
||||
},
|
||||
result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"},
|
||||
},
|
||||
{
|
||||
name: "resource selection",
|
||||
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
|
||||
{Group: "one", Version: "a", Resource: "first"},
|
||||
{Group: "one", Version: "a", Resource: "second"},
|
||||
}},
|
||||
resourcePatterns: []schema.GroupVersionResource{
|
||||
{Group: AnyGroup, Version: AnyVersion, Resource: "second"},
|
||||
},
|
||||
result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "second"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
mapper := PriorityRESTMapper{Delegate: tc.delegate, ResourcePriority: tc.resourcePatterns}
|
||||
|
||||
actualResult, actualErr := mapper.ResourceFor(schema.GroupVersionResource{})
|
||||
if e, a := tc.result, actualResult; e != a {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
if len(tc.err) == 0 && actualErr == nil {
|
||||
continue
|
||||
}
|
||||
if len(tc.err) > 0 && actualErr == nil {
|
||||
t.Errorf("%s: missing expected err: %v", tc.name, tc.err)
|
||||
continue
|
||||
}
|
||||
if !strings.Contains(actualErr.Error(), tc.err) {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPriorityRESTMapperKindForErrorHandling(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
delegate RESTMapper
|
||||
kindPatterns []schema.GroupVersionKind
|
||||
result schema.GroupVersionKind
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "single hit",
|
||||
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "single-hit"}}},
|
||||
result: schema.GroupVersionKind{Kind: "single-hit"},
|
||||
},
|
||||
{
|
||||
name: "ambiguous match",
|
||||
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: "a", Kind: "first"},
|
||||
{Group: "two", Version: "b", Kind: "second"},
|
||||
}},
|
||||
err: "matches multiple kinds",
|
||||
},
|
||||
{
|
||||
name: "group selection",
|
||||
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: "a", Kind: "first"},
|
||||
{Group: "two", Version: "b", Kind: "second"},
|
||||
}},
|
||||
kindPatterns: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: AnyVersion, Kind: AnyKind},
|
||||
},
|
||||
result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"},
|
||||
},
|
||||
{
|
||||
name: "empty match continues",
|
||||
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: "a", Kind: "first"},
|
||||
{Group: "two", Version: "b", Kind: "second"},
|
||||
}},
|
||||
kindPatterns: []schema.GroupVersionKind{
|
||||
{Group: "fail", Version: AnyVersion, Kind: AnyKind},
|
||||
{Group: "one", Version: AnyVersion, Kind: AnyKind},
|
||||
},
|
||||
result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"},
|
||||
},
|
||||
{
|
||||
name: "group followed by version selection",
|
||||
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: "a", Kind: "first"},
|
||||
{Group: "two", Version: "b", Kind: "second"},
|
||||
{Group: "one", Version: "c", Kind: "third"},
|
||||
}},
|
||||
kindPatterns: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: AnyVersion, Kind: AnyKind},
|
||||
{Group: AnyGroup, Version: "a", Kind: AnyKind},
|
||||
},
|
||||
result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"},
|
||||
},
|
||||
{
|
||||
name: "kind selection",
|
||||
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
|
||||
{Group: "one", Version: "a", Kind: "first"},
|
||||
{Group: "one", Version: "a", Kind: "second"},
|
||||
}},
|
||||
kindPatterns: []schema.GroupVersionKind{
|
||||
{Group: AnyGroup, Version: AnyVersion, Kind: "second"},
|
||||
},
|
||||
result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "second"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
mapper := PriorityRESTMapper{Delegate: tc.delegate, KindPriority: tc.kindPatterns}
|
||||
|
||||
actualResult, actualErr := mapper.KindFor(schema.GroupVersionResource{})
|
||||
if e, a := tc.result, actualResult; e != a {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
if len(tc.err) == 0 && actualErr == nil {
|
||||
continue
|
||||
}
|
||||
if len(tc.err) > 0 && actualErr == nil {
|
||||
t.Errorf("%s: missing expected err: %v", tc.name, tc.err)
|
||||
continue
|
||||
}
|
||||
if !strings.Contains(actualErr.Error(), tc.err) {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPriorityRESTMapperRESTMapping(t *testing.T) {
|
||||
mapping1 := &RESTMapping{
|
||||
GroupVersionKind: schema.GroupVersionKind{Kind: "Foo", Version: "v1alpha1"},
|
||||
}
|
||||
mapping2 := &RESTMapping{
|
||||
GroupVersionKind: schema.GroupVersionKind{Kind: "Foo", Version: "v1"},
|
||||
}
|
||||
mapping3 := &RESTMapping{
|
||||
GroupVersionKind: schema.GroupVersionKind{Group: "other", Kind: "Foo", Version: "v1"},
|
||||
}
|
||||
allMappers := MultiRESTMapper{
|
||||
fixedRESTMapper{mappings: []*RESTMapping{mapping1}},
|
||||
fixedRESTMapper{mappings: []*RESTMapping{mapping2}},
|
||||
fixedRESTMapper{mappings: []*RESTMapping{mapping3}},
|
||||
}
|
||||
tcs := []struct {
|
||||
name string
|
||||
|
||||
mapper PriorityRESTMapper
|
||||
input schema.GroupKind
|
||||
result *RESTMapping
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{}},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}},
|
||||
},
|
||||
{
|
||||
name: "ignore not found",
|
||||
mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "IGNORE_THIS"}}}}},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}},
|
||||
},
|
||||
{
|
||||
name: "accept first failure",
|
||||
mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{mappings: []*RESTMapping{mapping1}}}},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
err: errors.New("fail on this"),
|
||||
},
|
||||
{
|
||||
name: "return error for ambiguous",
|
||||
mapper: PriorityRESTMapper{
|
||||
Delegate: allMappers,
|
||||
},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
err: &AmbiguousKindError{
|
||||
PartialKind: schema.GroupVersionKind{Kind: "Foo"},
|
||||
MatchingKinds: []schema.GroupVersionKind{
|
||||
{Kind: "Foo", Version: "v1alpha1"},
|
||||
{Kind: "Foo", Version: "v1"},
|
||||
{Group: "other", Kind: "Foo", Version: "v1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "accept only item",
|
||||
mapper: PriorityRESTMapper{
|
||||
Delegate: fixedRESTMapper{mappings: []*RESTMapping{mapping1}},
|
||||
},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: mapping1,
|
||||
},
|
||||
{
|
||||
name: "return single priority",
|
||||
mapper: PriorityRESTMapper{
|
||||
Delegate: allMappers,
|
||||
KindPriority: []schema.GroupVersionKind{{Version: "v1", Kind: AnyKind}, {Version: "v1alpha1", Kind: AnyKind}},
|
||||
},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: mapping2,
|
||||
},
|
||||
{
|
||||
name: "return out of group match",
|
||||
mapper: PriorityRESTMapper{
|
||||
Delegate: allMappers,
|
||||
KindPriority: []schema.GroupVersionKind{{Group: AnyGroup, Version: "v1", Kind: AnyKind}, {Group: "other", Version: AnyVersion, Kind: AnyKind}},
|
||||
},
|
||||
input: schema.GroupKind{Kind: "Foo"},
|
||||
result: mapping3,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
actualResult, actualErr := tc.mapper.RESTMapping(tc.input)
|
||||
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
|
||||
}
|
||||
switch {
|
||||
case tc.err == nil && actualErr == nil:
|
||||
case tc.err == nil:
|
||||
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
|
||||
case actualErr == nil:
|
||||
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
|
||||
case tc.err.Error() != actualErr.Error():
|
||||
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPriorityRESTMapperRESTMappingHonorsUserVersion(t *testing.T) {
|
||||
mappingV2alpha1 := &RESTMapping{
|
||||
GroupVersionKind: schema.GroupVersionKind{Group: "Bar", Kind: "Foo", Version: "v2alpha1"},
|
||||
}
|
||||
mappingV1 := &RESTMapping{
|
||||
GroupVersionKind: schema.GroupVersionKind{Group: "Bar", Kind: "Foo", Version: "v1"},
|
||||
}
|
||||
|
||||
allMappers := MultiRESTMapper{
|
||||
fixedRESTMapper{mappings: []*RESTMapping{mappingV2alpha1}},
|
||||
fixedRESTMapper{mappings: []*RESTMapping{mappingV1}},
|
||||
}
|
||||
|
||||
mapper := PriorityRESTMapper{
|
||||
Delegate: allMappers,
|
||||
KindPriority: []schema.GroupVersionKind{{Group: "Bar", Version: "v2alpha1", Kind: AnyKind}, {Group: "Bar", Version: AnyVersion, Kind: AnyKind}},
|
||||
}
|
||||
|
||||
outMapping1, err := mapper.RESTMapping(schema.GroupKind{Group: "Bar", Kind: "Foo"}, "v1")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if outMapping1 != mappingV1 {
|
||||
t.Errorf("asked for version %v, expected mapping for %v, got mapping for %v", "v1", mappingV1.GroupVersionKind, outMapping1.GroupVersionKind)
|
||||
}
|
||||
|
||||
outMapping2, err := mapper.RESTMapping(schema.GroupKind{Group: "Bar", Kind: "Foo"}, "v2alpha1")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if outMapping2 != mappingV2alpha1 {
|
||||
t.Errorf("asked for version %v, expected mapping for %v, got mapping for %v", "v2alpha1", mappingV2alpha1.GroupVersionKind, outMapping2.GroupVersionKind)
|
||||
}
|
||||
}
|
548
vendor/k8s.io/apimachinery/pkg/api/meta/restmapper.go
generated
vendored
Normal file
548
vendor/k8s.io/apimachinery/pkg/api/meta/restmapper.go
generated
vendored
Normal file
@ -0,0 +1,548 @@
|
||||
/*
|
||||
Copyright 2014 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.
|
||||
*/
|
||||
|
||||
// TODO: move everything in this file to pkg/api/rest
|
||||
package meta
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// Implements RESTScope interface
|
||||
type restScope struct {
|
||||
name RESTScopeName
|
||||
paramName string
|
||||
argumentName string
|
||||
paramDescription string
|
||||
}
|
||||
|
||||
func (r *restScope) Name() RESTScopeName {
|
||||
return r.name
|
||||
}
|
||||
func (r *restScope) ParamName() string {
|
||||
return r.paramName
|
||||
}
|
||||
func (r *restScope) ArgumentName() string {
|
||||
return r.argumentName
|
||||
}
|
||||
func (r *restScope) ParamDescription() string {
|
||||
return r.paramDescription
|
||||
}
|
||||
|
||||
var RESTScopeNamespace = &restScope{
|
||||
name: RESTScopeNameNamespace,
|
||||
paramName: "namespaces",
|
||||
argumentName: "namespace",
|
||||
paramDescription: "object name and auth scope, such as for teams and projects",
|
||||
}
|
||||
|
||||
var RESTScopeRoot = &restScope{
|
||||
name: RESTScopeNameRoot,
|
||||
}
|
||||
|
||||
// DefaultRESTMapper exposes mappings between the types defined in a
|
||||
// runtime.Scheme. It assumes that all types defined the provided scheme
|
||||
// can be mapped with the provided MetadataAccessor and Codec interfaces.
|
||||
//
|
||||
// The resource name of a Kind is defined as the lowercase,
|
||||
// English-plural version of the Kind string.
|
||||
// When converting from resource to Kind, the singular version of the
|
||||
// resource name is also accepted for convenience.
|
||||
//
|
||||
// TODO: Only accept plural for some operations for increased control?
|
||||
// (`get pod bar` vs `get pods bar`)
|
||||
type DefaultRESTMapper struct {
|
||||
defaultGroupVersions []schema.GroupVersion
|
||||
|
||||
resourceToKind map[schema.GroupVersionResource]schema.GroupVersionKind
|
||||
kindToPluralResource map[schema.GroupVersionKind]schema.GroupVersionResource
|
||||
kindToScope map[schema.GroupVersionKind]RESTScope
|
||||
singularToPlural map[schema.GroupVersionResource]schema.GroupVersionResource
|
||||
pluralToSingular map[schema.GroupVersionResource]schema.GroupVersionResource
|
||||
|
||||
interfacesFunc VersionInterfacesFunc
|
||||
}
|
||||
|
||||
func (m *DefaultRESTMapper) String() string {
|
||||
return fmt.Sprintf("DefaultRESTMapper{kindToPluralResource=%v}", m.kindToPluralResource)
|
||||
}
|
||||
|
||||
var _ RESTMapper = &DefaultRESTMapper{}
|
||||
|
||||
// VersionInterfacesFunc returns the appropriate typer, and metadata accessor for a
|
||||
// given api version, or an error if no such api version exists.
|
||||
type VersionInterfacesFunc func(version schema.GroupVersion) (*VersionInterfaces, error)
|
||||
|
||||
// NewDefaultRESTMapper initializes a mapping between Kind and APIVersion
|
||||
// to a resource name and back based on the objects in a runtime.Scheme
|
||||
// and the Kubernetes API conventions. Takes a group name, a priority list of the versions
|
||||
// to search when an object has no default version (set empty to return an error),
|
||||
// and a function that retrieves the correct metadata for a given version.
|
||||
func NewDefaultRESTMapper(defaultGroupVersions []schema.GroupVersion, f VersionInterfacesFunc) *DefaultRESTMapper {
|
||||
resourceToKind := make(map[schema.GroupVersionResource]schema.GroupVersionKind)
|
||||
kindToPluralResource := make(map[schema.GroupVersionKind]schema.GroupVersionResource)
|
||||
kindToScope := make(map[schema.GroupVersionKind]RESTScope)
|
||||
singularToPlural := make(map[schema.GroupVersionResource]schema.GroupVersionResource)
|
||||
pluralToSingular := make(map[schema.GroupVersionResource]schema.GroupVersionResource)
|
||||
// TODO: verify name mappings work correctly when versions differ
|
||||
|
||||
return &DefaultRESTMapper{
|
||||
resourceToKind: resourceToKind,
|
||||
kindToPluralResource: kindToPluralResource,
|
||||
kindToScope: kindToScope,
|
||||
defaultGroupVersions: defaultGroupVersions,
|
||||
singularToPlural: singularToPlural,
|
||||
pluralToSingular: pluralToSingular,
|
||||
interfacesFunc: f,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *DefaultRESTMapper) Add(kind schema.GroupVersionKind, scope RESTScope) {
|
||||
plural, singular := UnsafeGuessKindToResource(kind)
|
||||
m.AddSpecific(kind, plural, singular, scope)
|
||||
}
|
||||
|
||||
func (m *DefaultRESTMapper) AddSpecific(kind schema.GroupVersionKind, plural, singular schema.GroupVersionResource, scope RESTScope) {
|
||||
m.singularToPlural[singular] = plural
|
||||
m.pluralToSingular[plural] = singular
|
||||
|
||||
m.resourceToKind[singular] = kind
|
||||
m.resourceToKind[plural] = kind
|
||||
|
||||
m.kindToPluralResource[kind] = plural
|
||||
m.kindToScope[kind] = scope
|
||||
}
|
||||
|
||||
// unpluralizedSuffixes is a list of resource suffixes that are the same plural and singular
|
||||
// This is only is only necessary because some bits of code are lazy and don't actually use the RESTMapper like they should.
|
||||
// TODO eliminate this so that different callers can correctly map to resources. This probably means updating all
|
||||
// callers to use the RESTMapper they mean.
|
||||
var unpluralizedSuffixes = []string{
|
||||
"endpoints",
|
||||
}
|
||||
|
||||
// UnsafeGuessKindToResource converts Kind to a resource name.
|
||||
// Broken. This method only "sort of" works when used outside of this package. It assumes that Kinds and Resources match
|
||||
// and they aren't guaranteed to do so.
|
||||
func UnsafeGuessKindToResource(kind schema.GroupVersionKind) ( /*plural*/ schema.GroupVersionResource /*singular*/, schema.GroupVersionResource) {
|
||||
kindName := kind.Kind
|
||||
if len(kindName) == 0 {
|
||||
return schema.GroupVersionResource{}, schema.GroupVersionResource{}
|
||||
}
|
||||
singularName := strings.ToLower(kindName)
|
||||
singular := kind.GroupVersion().WithResource(singularName)
|
||||
|
||||
for _, skip := range unpluralizedSuffixes {
|
||||
if strings.HasSuffix(singularName, skip) {
|
||||
return singular, singular
|
||||
}
|
||||
}
|
||||
|
||||
switch string(singularName[len(singularName)-1]) {
|
||||
case "s":
|
||||
return kind.GroupVersion().WithResource(singularName + "es"), singular
|
||||
case "y":
|
||||
return kind.GroupVersion().WithResource(strings.TrimSuffix(singularName, "y") + "ies"), singular
|
||||
}
|
||||
|
||||
return kind.GroupVersion().WithResource(singularName + "s"), singular
|
||||
}
|
||||
|
||||
// ResourceSingularizer implements RESTMapper
|
||||
// It converts a resource name from plural to singular (e.g., from pods to pod)
|
||||
func (m *DefaultRESTMapper) ResourceSingularizer(resourceType string) (string, error) {
|
||||
partialResource := schema.GroupVersionResource{Resource: resourceType}
|
||||
resources, err := m.ResourcesFor(partialResource)
|
||||
if err != nil {
|
||||
return resourceType, err
|
||||
}
|
||||
|
||||
singular := schema.GroupVersionResource{}
|
||||
for _, curr := range resources {
|
||||
currSingular, ok := m.pluralToSingular[curr]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if singular.Empty() {
|
||||
singular = currSingular
|
||||
continue
|
||||
}
|
||||
|
||||
if currSingular.Resource != singular.Resource {
|
||||
return resourceType, fmt.Errorf("multiple possible singular resources (%v) found for %v", resources, resourceType)
|
||||
}
|
||||
}
|
||||
|
||||
if singular.Empty() {
|
||||
return resourceType, fmt.Errorf("no singular of resource %v has been defined", resourceType)
|
||||
}
|
||||
|
||||
return singular.Resource, nil
|
||||
}
|
||||
|
||||
// coerceResourceForMatching makes the resource lower case and converts internal versions to unspecified (legacy behavior)
|
||||
func coerceResourceForMatching(resource schema.GroupVersionResource) schema.GroupVersionResource {
|
||||
resource.Resource = strings.ToLower(resource.Resource)
|
||||
if resource.Version == runtime.APIVersionInternal {
|
||||
resource.Version = ""
|
||||
}
|
||||
|
||||
return resource
|
||||
}
|
||||
|
||||
func (m *DefaultRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
|
||||
resource := coerceResourceForMatching(input)
|
||||
|
||||
hasResource := len(resource.Resource) > 0
|
||||
hasGroup := len(resource.Group) > 0
|
||||
hasVersion := len(resource.Version) > 0
|
||||
|
||||
if !hasResource {
|
||||
return nil, fmt.Errorf("a resource must be present, got: %v", resource)
|
||||
}
|
||||
|
||||
ret := []schema.GroupVersionResource{}
|
||||
switch {
|
||||
case hasGroup && hasVersion:
|
||||
// fully qualified. Find the exact match
|
||||
for plural, singular := range m.pluralToSingular {
|
||||
if singular == resource {
|
||||
ret = append(ret, plural)
|
||||
break
|
||||
}
|
||||
if plural == resource {
|
||||
ret = append(ret, plural)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
case hasGroup:
|
||||
// given a group, prefer an exact match. If you don't find one, resort to a prefix match on group
|
||||
foundExactMatch := false
|
||||
requestedGroupResource := resource.GroupResource()
|
||||
for plural, singular := range m.pluralToSingular {
|
||||
if singular.GroupResource() == requestedGroupResource {
|
||||
foundExactMatch = true
|
||||
ret = append(ret, plural)
|
||||
}
|
||||
if plural.GroupResource() == requestedGroupResource {
|
||||
foundExactMatch = true
|
||||
ret = append(ret, plural)
|
||||
}
|
||||
}
|
||||
|
||||
// if you didn't find an exact match, match on group prefixing. This allows storageclass.storage to match
|
||||
// storageclass.storage.k8s.io
|
||||
if !foundExactMatch {
|
||||
for plural, singular := range m.pluralToSingular {
|
||||
if !strings.HasPrefix(plural.Group, requestedGroupResource.Group) {
|
||||
continue
|
||||
}
|
||||
if singular.Resource == requestedGroupResource.Resource {
|
||||
ret = append(ret, plural)
|
||||
}
|
||||
if plural.Resource == requestedGroupResource.Resource {
|
||||
ret = append(ret, plural)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case hasVersion:
|
||||
for plural, singular := range m.pluralToSingular {
|
||||
if singular.Version == resource.Version && singular.Resource == resource.Resource {
|
||||
ret = append(ret, plural)
|
||||
}
|
||||
if plural.Version == resource.Version && plural.Resource == resource.Resource {
|
||||
ret = append(ret, plural)
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
for plural, singular := range m.pluralToSingular {
|
||||
if singular.Resource == resource.Resource {
|
||||
ret = append(ret, plural)
|
||||
}
|
||||
if plural.Resource == resource.Resource {
|
||||
ret = append(ret, plural)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(ret) == 0 {
|
||||
return nil, &NoResourceMatchError{PartialResource: resource}
|
||||
}
|
||||
|
||||
sort.Sort(resourceByPreferredGroupVersion{ret, m.defaultGroupVersions})
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (m *DefaultRESTMapper) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
|
||||
resources, err := m.ResourcesFor(resource)
|
||||
if err != nil {
|
||||
return schema.GroupVersionResource{}, err
|
||||
}
|
||||
if len(resources) == 1 {
|
||||
return resources[0], nil
|
||||
}
|
||||
|
||||
return schema.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: resource, MatchingResources: resources}
|
||||
}
|
||||
|
||||
func (m *DefaultRESTMapper) KindsFor(input schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
|
||||
resource := coerceResourceForMatching(input)
|
||||
|
||||
hasResource := len(resource.Resource) > 0
|
||||
hasGroup := len(resource.Group) > 0
|
||||
hasVersion := len(resource.Version) > 0
|
||||
|
||||
if !hasResource {
|
||||
return nil, fmt.Errorf("a resource must be present, got: %v", resource)
|
||||
}
|
||||
|
||||
ret := []schema.GroupVersionKind{}
|
||||
switch {
|
||||
// fully qualified. Find the exact match
|
||||
case hasGroup && hasVersion:
|
||||
kind, exists := m.resourceToKind[resource]
|
||||
if exists {
|
||||
ret = append(ret, kind)
|
||||
}
|
||||
|
||||
case hasGroup:
|
||||
foundExactMatch := false
|
||||
requestedGroupResource := resource.GroupResource()
|
||||
for currResource, currKind := range m.resourceToKind {
|
||||
if currResource.GroupResource() == requestedGroupResource {
|
||||
foundExactMatch = true
|
||||
ret = append(ret, currKind)
|
||||
}
|
||||
}
|
||||
|
||||
// if you didn't find an exact match, match on group prefixing. This allows storageclass.storage to match
|
||||
// storageclass.storage.k8s.io
|
||||
if !foundExactMatch {
|
||||
for currResource, currKind := range m.resourceToKind {
|
||||
if !strings.HasPrefix(currResource.Group, requestedGroupResource.Group) {
|
||||
continue
|
||||
}
|
||||
if currResource.Resource == requestedGroupResource.Resource {
|
||||
ret = append(ret, currKind)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case hasVersion:
|
||||
for currResource, currKind := range m.resourceToKind {
|
||||
if currResource.Version == resource.Version && currResource.Resource == resource.Resource {
|
||||
ret = append(ret, currKind)
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
for currResource, currKind := range m.resourceToKind {
|
||||
if currResource.Resource == resource.Resource {
|
||||
ret = append(ret, currKind)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(ret) == 0 {
|
||||
return nil, &NoResourceMatchError{PartialResource: input}
|
||||
}
|
||||
|
||||
sort.Sort(kindByPreferredGroupVersion{ret, m.defaultGroupVersions})
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (m *DefaultRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||
kinds, err := m.KindsFor(resource)
|
||||
if err != nil {
|
||||
return schema.GroupVersionKind{}, err
|
||||
}
|
||||
if len(kinds) == 1 {
|
||||
return kinds[0], nil
|
||||
}
|
||||
|
||||
return schema.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: resource, MatchingKinds: kinds}
|
||||
}
|
||||
|
||||
type kindByPreferredGroupVersion struct {
|
||||
list []schema.GroupVersionKind
|
||||
sortOrder []schema.GroupVersion
|
||||
}
|
||||
|
||||
func (o kindByPreferredGroupVersion) Len() int { return len(o.list) }
|
||||
func (o kindByPreferredGroupVersion) Swap(i, j int) { o.list[i], o.list[j] = o.list[j], o.list[i] }
|
||||
func (o kindByPreferredGroupVersion) Less(i, j int) bool {
|
||||
lhs := o.list[i]
|
||||
rhs := o.list[j]
|
||||
if lhs == rhs {
|
||||
return false
|
||||
}
|
||||
|
||||
if lhs.GroupVersion() == rhs.GroupVersion() {
|
||||
return lhs.Kind < rhs.Kind
|
||||
}
|
||||
|
||||
// otherwise, the difference is in the GroupVersion, so we need to sort with respect to the preferred order
|
||||
lhsIndex := -1
|
||||
rhsIndex := -1
|
||||
|
||||
for i := range o.sortOrder {
|
||||
if o.sortOrder[i] == lhs.GroupVersion() {
|
||||
lhsIndex = i
|
||||
}
|
||||
if o.sortOrder[i] == rhs.GroupVersion() {
|
||||
rhsIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
if rhsIndex == -1 {
|
||||
return true
|
||||
}
|
||||
|
||||
return lhsIndex < rhsIndex
|
||||
}
|
||||
|
||||
type resourceByPreferredGroupVersion struct {
|
||||
list []schema.GroupVersionResource
|
||||
sortOrder []schema.GroupVersion
|
||||
}
|
||||
|
||||
func (o resourceByPreferredGroupVersion) Len() int { return len(o.list) }
|
||||
func (o resourceByPreferredGroupVersion) Swap(i, j int) { o.list[i], o.list[j] = o.list[j], o.list[i] }
|
||||
func (o resourceByPreferredGroupVersion) Less(i, j int) bool {
|
||||
lhs := o.list[i]
|
||||
rhs := o.list[j]
|
||||
if lhs == rhs {
|
||||
return false
|
||||
}
|
||||
|
||||
if lhs.GroupVersion() == rhs.GroupVersion() {
|
||||
return lhs.Resource < rhs.Resource
|
||||
}
|
||||
|
||||
// otherwise, the difference is in the GroupVersion, so we need to sort with respect to the preferred order
|
||||
lhsIndex := -1
|
||||
rhsIndex := -1
|
||||
|
||||
for i := range o.sortOrder {
|
||||
if o.sortOrder[i] == lhs.GroupVersion() {
|
||||
lhsIndex = i
|
||||
}
|
||||
if o.sortOrder[i] == rhs.GroupVersion() {
|
||||
rhsIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
if rhsIndex == -1 {
|
||||
return true
|
||||
}
|
||||
|
||||
return lhsIndex < rhsIndex
|
||||
}
|
||||
|
||||
// RESTMapping returns a struct representing the resource path and conversion interfaces a
|
||||
// RESTClient should use to operate on the provided group/kind in order of versions. If a version search
|
||||
// order is not provided, the search order provided to DefaultRESTMapper will be used to resolve which
|
||||
// version should be used to access the named group/kind.
|
||||
func (m *DefaultRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error) {
|
||||
mappings, err := m.RESTMappings(gk, versions...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(mappings) == 0 {
|
||||
return nil, &NoKindMatchError{PartialKind: gk.WithVersion("")}
|
||||
}
|
||||
// since we rely on RESTMappings method
|
||||
// take the first match and return to the caller
|
||||
// as this was the existing behavior.
|
||||
return mappings[0], nil
|
||||
}
|
||||
|
||||
// RESTMappings returns the RESTMappings for the provided group kind. If a version search order
|
||||
// is not provided, the search order provided to DefaultRESTMapper will be used.
|
||||
func (m *DefaultRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error) {
|
||||
mappings := make([]*RESTMapping, 0)
|
||||
potentialGVK := make([]schema.GroupVersionKind, 0)
|
||||
hadVersion := false
|
||||
|
||||
// Pick an appropriate version
|
||||
for _, version := range versions {
|
||||
if len(version) == 0 || version == runtime.APIVersionInternal {
|
||||
continue
|
||||
}
|
||||
currGVK := gk.WithVersion(version)
|
||||
hadVersion = true
|
||||
if _, ok := m.kindToPluralResource[currGVK]; ok {
|
||||
potentialGVK = append(potentialGVK, currGVK)
|
||||
break
|
||||
}
|
||||
}
|
||||
// Use the default preferred versions
|
||||
if !hadVersion && len(potentialGVK) == 0 {
|
||||
for _, gv := range m.defaultGroupVersions {
|
||||
if gv.Group != gk.Group {
|
||||
continue
|
||||
}
|
||||
potentialGVK = append(potentialGVK, gk.WithVersion(gv.Version))
|
||||
}
|
||||
}
|
||||
|
||||
if len(potentialGVK) == 0 {
|
||||
return nil, &NoKindMatchError{PartialKind: gk.WithVersion("")}
|
||||
}
|
||||
|
||||
for _, gvk := range potentialGVK {
|
||||
//Ensure we have a REST mapping
|
||||
res, ok := m.kindToPluralResource[gvk]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Ensure we have a REST scope
|
||||
scope, ok := m.kindToScope[gvk]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported scope", gvk.GroupVersion(), gvk.Kind)
|
||||
}
|
||||
|
||||
interfaces, err := m.interfacesFunc(gvk.GroupVersion())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("the provided version %q has no relevant versions: %v", gvk.GroupVersion().String(), err)
|
||||
}
|
||||
|
||||
mappings = append(mappings, &RESTMapping{
|
||||
Resource: res.Resource,
|
||||
GroupVersionKind: gvk,
|
||||
Scope: scope,
|
||||
|
||||
ObjectConvertor: interfaces.ObjectConvertor,
|
||||
MetadataAccessor: interfaces.MetadataAccessor,
|
||||
})
|
||||
}
|
||||
|
||||
if len(mappings) == 0 {
|
||||
return nil, &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Group: gk.Group, Resource: gk.Kind}}
|
||||
}
|
||||
return mappings, nil
|
||||
}
|
751
vendor/k8s.io/apimachinery/pkg/api/meta/restmapper_test.go
generated
vendored
Normal file
751
vendor/k8s.io/apimachinery/pkg/api/meta/restmapper_test.go
generated
vendored
Normal file
@ -0,0 +1,751 @@
|
||||
/*
|
||||
Copyright 2014 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 meta
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
type fakeConvertor struct{}
|
||||
|
||||
func (fakeConvertor) Convert(in, out, context interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fakeConvertor) ConvertToVersion(in runtime.Object, _ runtime.GroupVersioner) (runtime.Object, error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func (fakeConvertor) ConvertFieldLabel(version, kind, label, value string) (string, string, error) {
|
||||
return label, value, nil
|
||||
}
|
||||
|
||||
var validAccessor = resourceAccessor{}
|
||||
var validConvertor = fakeConvertor{}
|
||||
|
||||
func fakeInterfaces(version schema.GroupVersion) (*VersionInterfaces, error) {
|
||||
return &VersionInterfaces{ObjectConvertor: validConvertor, MetadataAccessor: validAccessor}, nil
|
||||
}
|
||||
|
||||
var unmatchedErr = errors.New("no version")
|
||||
|
||||
func unmatchedVersionInterfaces(version schema.GroupVersion) (*VersionInterfaces, error) {
|
||||
return nil, unmatchedErr
|
||||
}
|
||||
|
||||
func TestRESTMapperVersionAndKindForResource(t *testing.T) {
|
||||
testGroup := "test.group"
|
||||
testVersion := "test"
|
||||
testGroupVersion := schema.GroupVersion{Group: testGroup, Version: testVersion}
|
||||
|
||||
testCases := []struct {
|
||||
Resource schema.GroupVersionResource
|
||||
GroupVersionToRegister schema.GroupVersion
|
||||
ExpectedGVK schema.GroupVersionKind
|
||||
Err bool
|
||||
}{
|
||||
{Resource: schema.GroupVersionResource{Resource: "internalobjec"}, Err: true},
|
||||
{Resource: schema.GroupVersionResource{Resource: "internalObjec"}, Err: true},
|
||||
|
||||
{Resource: schema.GroupVersionResource{Resource: "internalobject"}, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
|
||||
{Resource: schema.GroupVersionResource{Resource: "internalobjects"}, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper([]schema.GroupVersion{testGroupVersion}, fakeInterfaces)
|
||||
if len(testCase.ExpectedGVK.Kind) != 0 {
|
||||
mapper.Add(testCase.ExpectedGVK, RESTScopeNamespace)
|
||||
}
|
||||
actualGVK, err := mapper.KindFor(testCase.Resource)
|
||||
|
||||
hasErr := err != nil
|
||||
if hasErr != testCase.Err {
|
||||
t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if actualGVK != testCase.ExpectedGVK {
|
||||
t.Errorf("%d: unexpected version and kind: e=%s a=%s", i, testCase.ExpectedGVK, actualGVK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperGroupForResource(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Resource schema.GroupVersionResource
|
||||
GroupVersionKind schema.GroupVersionKind
|
||||
Err bool
|
||||
}{
|
||||
{Resource: schema.GroupVersionResource{Resource: "myObject"}, GroupVersionKind: schema.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
|
||||
{Resource: schema.GroupVersionResource{Resource: "myobject"}, GroupVersionKind: schema.GroupVersionKind{Group: "testapi2", Version: "test", Kind: "MyObject"}},
|
||||
{Resource: schema.GroupVersionResource{Resource: "myObje"}, Err: true, GroupVersionKind: schema.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
|
||||
{Resource: schema.GroupVersionResource{Resource: "myobje"}, Err: true, GroupVersionKind: schema.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper([]schema.GroupVersion{testCase.GroupVersionKind.GroupVersion()}, fakeInterfaces)
|
||||
mapper.Add(testCase.GroupVersionKind, RESTScopeNamespace)
|
||||
|
||||
actualGVK, err := mapper.KindFor(testCase.Resource)
|
||||
if testCase.Err {
|
||||
if err == nil {
|
||||
t.Errorf("%d: expected error", i)
|
||||
}
|
||||
} else if err != nil {
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
} else if actualGVK != testCase.GroupVersionKind {
|
||||
t.Errorf("%d: expected group %q, got %q", i, testCase.GroupVersionKind, actualGVK)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperKindsFor(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
PreferredOrder []schema.GroupVersion
|
||||
KindsToRegister []schema.GroupVersionKind
|
||||
PartialResourceToRequest schema.GroupVersionResource
|
||||
|
||||
ExpectedKinds []schema.GroupVersionKind
|
||||
ExpectedKindErr string
|
||||
}{
|
||||
{
|
||||
// exact matches are preferred
|
||||
Name: "groups, with group exact",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "first-group-1", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group-1", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
PartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kind"},
|
||||
|
||||
ExpectedKinds: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// group prefixes work
|
||||
Name: "groups, with group prefix",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
PartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kind"},
|
||||
|
||||
ExpectedKinds: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// group prefixes can be ambiguous
|
||||
Name: "groups, with ambiguous group prefix",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "first-group-1", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group-1", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
PartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kind"},
|
||||
|
||||
ExpectedKinds: []schema.GroupVersionKind{
|
||||
{Group: "first-group-1", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
ExpectedKindErr: " matches multiple kinds ",
|
||||
},
|
||||
|
||||
{
|
||||
Name: "ambiguous groups, with preference order",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
|
||||
},
|
||||
PartialResourceToRequest: schema.GroupVersionResource{Resource: "my-kinds"},
|
||||
|
||||
ExpectedKinds: []schema.GroupVersionKind{
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
ExpectedKindErr: " matches multiple kinds ",
|
||||
},
|
||||
|
||||
{
|
||||
Name: "ambiguous groups, with explicit group match",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
|
||||
},
|
||||
PartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kinds"},
|
||||
|
||||
ExpectedKinds: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Name: "ambiguous groups, with ambiguous version match",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
|
||||
},
|
||||
PartialResourceToRequest: schema.GroupVersionResource{Version: "first-version", Resource: "my-kinds"},
|
||||
|
||||
ExpectedKinds: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
ExpectedKindErr: " matches multiple kinds ",
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
tcName := testCase.Name
|
||||
mapper := NewDefaultRESTMapper(testCase.PreferredOrder, fakeInterfaces)
|
||||
for _, kind := range testCase.KindsToRegister {
|
||||
mapper.Add(kind, RESTScopeNamespace)
|
||||
}
|
||||
|
||||
actualKinds, err := mapper.KindsFor(testCase.PartialResourceToRequest)
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", tcName, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(testCase.ExpectedKinds, actualKinds) {
|
||||
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKinds, actualKinds)
|
||||
}
|
||||
|
||||
singleKind, err := mapper.KindFor(testCase.PartialResourceToRequest)
|
||||
if err == nil && len(testCase.ExpectedKindErr) != 0 {
|
||||
t.Errorf("%s: expected error: %v", tcName, testCase.ExpectedKindErr)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
if len(testCase.ExpectedKindErr) == 0 {
|
||||
t.Errorf("%s: unexpected error: %v", tcName, err)
|
||||
continue
|
||||
} else {
|
||||
if !strings.Contains(err.Error(), testCase.ExpectedKindErr) {
|
||||
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKindErr, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if testCase.ExpectedKinds[0] != singleKind {
|
||||
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKinds[0], singleKind)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperResourcesFor(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
PreferredOrder []schema.GroupVersion
|
||||
KindsToRegister []schema.GroupVersionKind
|
||||
PluralPartialResourceToRequest schema.GroupVersionResource
|
||||
SingularPartialResourceToRequest schema.GroupVersionResource
|
||||
|
||||
ExpectedResources []schema.GroupVersionResource
|
||||
ExpectedResourceErr string
|
||||
}{
|
||||
{
|
||||
// exact matches are preferred
|
||||
Name: "groups, with group exact",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "first-group-1", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group-1", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
PluralPartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kinds"},
|
||||
SingularPartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kind"},
|
||||
|
||||
ExpectedResources: []schema.GroupVersionResource{
|
||||
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// group prefixes work
|
||||
Name: "groups, with group prefix",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
PluralPartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kinds"},
|
||||
SingularPartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kind"},
|
||||
|
||||
ExpectedResources: []schema.GroupVersionResource{
|
||||
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// group prefixes can be ambiguous
|
||||
Name: "groups, with ambiguous group prefix",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "first-group-1", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group-1", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
},
|
||||
PluralPartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kinds"},
|
||||
SingularPartialResourceToRequest: schema.GroupVersionResource{Group: "first", Resource: "my-kind"},
|
||||
|
||||
ExpectedResources: []schema.GroupVersionResource{
|
||||
{Group: "first-group-1", Version: "first-version", Resource: "my-kinds"},
|
||||
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
|
||||
},
|
||||
ExpectedResourceErr: " matches multiple resources ",
|
||||
},
|
||||
|
||||
{
|
||||
Name: "ambiguous groups, with preference order",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
|
||||
},
|
||||
PluralPartialResourceToRequest: schema.GroupVersionResource{Resource: "my-kinds"},
|
||||
SingularPartialResourceToRequest: schema.GroupVersionResource{Resource: "my-kind"},
|
||||
|
||||
ExpectedResources: []schema.GroupVersionResource{
|
||||
{Group: "second-group", Version: "first-version", Resource: "my-kinds"},
|
||||
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
|
||||
},
|
||||
ExpectedResourceErr: " matches multiple resources ",
|
||||
},
|
||||
|
||||
{
|
||||
Name: "ambiguous groups, with explicit group match",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
|
||||
},
|
||||
PluralPartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kinds"},
|
||||
SingularPartialResourceToRequest: schema.GroupVersionResource{Group: "first-group", Resource: "my-kind"},
|
||||
|
||||
ExpectedResources: []schema.GroupVersionResource{
|
||||
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Name: "ambiguous groups, with ambiguous version match",
|
||||
PreferredOrder: []schema.GroupVersion{
|
||||
{Group: "first-group", Version: "first-version"},
|
||||
{Group: "second-group", Version: "first-version"},
|
||||
},
|
||||
KindsToRegister: []schema.GroupVersionKind{
|
||||
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
|
||||
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
|
||||
},
|
||||
PluralPartialResourceToRequest: schema.GroupVersionResource{Version: "first-version", Resource: "my-kinds"},
|
||||
SingularPartialResourceToRequest: schema.GroupVersionResource{Version: "first-version", Resource: "my-kind"},
|
||||
|
||||
ExpectedResources: []schema.GroupVersionResource{
|
||||
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
|
||||
{Group: "second-group", Version: "first-version", Resource: "my-kinds"},
|
||||
},
|
||||
ExpectedResourceErr: " matches multiple resources ",
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
tcName := testCase.Name
|
||||
|
||||
for _, partialResource := range []schema.GroupVersionResource{testCase.PluralPartialResourceToRequest, testCase.SingularPartialResourceToRequest} {
|
||||
mapper := NewDefaultRESTMapper(testCase.PreferredOrder, fakeInterfaces)
|
||||
for _, kind := range testCase.KindsToRegister {
|
||||
mapper.Add(kind, RESTScopeNamespace)
|
||||
}
|
||||
|
||||
actualResources, err := mapper.ResourcesFor(partialResource)
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", tcName, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(testCase.ExpectedResources, actualResources) {
|
||||
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResources, actualResources)
|
||||
}
|
||||
|
||||
singleResource, err := mapper.ResourceFor(partialResource)
|
||||
if err == nil && len(testCase.ExpectedResourceErr) != 0 {
|
||||
t.Errorf("%s: expected error: %v", tcName, testCase.ExpectedResourceErr)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
if len(testCase.ExpectedResourceErr) == 0 {
|
||||
t.Errorf("%s: unexpected error: %v", tcName, err)
|
||||
continue
|
||||
} else {
|
||||
if !strings.Contains(err.Error(), testCase.ExpectedResourceErr) {
|
||||
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResourceErr, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if testCase.ExpectedResources[0] != singleResource {
|
||||
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResources[0], singleResource)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestKindToResource(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Kind string
|
||||
Plural, Singular string
|
||||
}{
|
||||
{Kind: "Pod", Plural: "pods", Singular: "pod"},
|
||||
|
||||
{Kind: "ReplicationController", Plural: "replicationcontrollers", Singular: "replicationcontroller"},
|
||||
|
||||
// Add "ies" when ending with "y"
|
||||
{Kind: "ImageRepository", Plural: "imagerepositories", Singular: "imagerepository"},
|
||||
// Add "es" when ending with "s"
|
||||
{Kind: "miss", Plural: "misses", Singular: "miss"},
|
||||
// Add "s" otherwise
|
||||
{Kind: "lowercase", Plural: "lowercases", Singular: "lowercase"},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
version := schema.GroupVersion{}
|
||||
|
||||
plural, singular := UnsafeGuessKindToResource(version.WithKind(testCase.Kind))
|
||||
if singular != version.WithResource(testCase.Singular) || plural != version.WithResource(testCase.Plural) {
|
||||
t.Errorf("%d: unexpected plural and singular: %v %v", i, plural, singular)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperResourceSingularizer(t *testing.T) {
|
||||
testGroupVersion := schema.GroupVersion{Group: "tgroup", Version: "test"}
|
||||
|
||||
testCases := []struct {
|
||||
Kind string
|
||||
Plural string
|
||||
Singular string
|
||||
}{
|
||||
{Kind: "Pod", Plural: "pods", Singular: "pod"},
|
||||
{Kind: "ReplicationController", Plural: "replicationcontrollers", Singular: "replicationcontroller"},
|
||||
{Kind: "ImageRepository", Plural: "imagerepositories", Singular: "imagerepository"},
|
||||
{Kind: "Status", Plural: "statuses", Singular: "status"},
|
||||
|
||||
{Kind: "lowercase", Plural: "lowercases", Singular: "lowercase"},
|
||||
// TODO this test is broken. This updates to reflect actual behavior. Kinds are expected to be singular
|
||||
// old (incorrect), coment: Don't add extra s if the original object is already plural
|
||||
{Kind: "lowercases", Plural: "lowercaseses", Singular: "lowercases"},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper([]schema.GroupVersion{testGroupVersion}, fakeInterfaces)
|
||||
// create singular/plural mapping
|
||||
mapper.Add(testGroupVersion.WithKind(testCase.Kind), RESTScopeNamespace)
|
||||
|
||||
singular, err := mapper.ResourceSingularizer(testCase.Plural)
|
||||
if err != nil {
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
}
|
||||
if singular != testCase.Singular {
|
||||
t.Errorf("%d: mismatched singular: got %v, expected %v", i, singular, testCase.Singular)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperRESTMapping(t *testing.T) {
|
||||
testGroup := "tgroup"
|
||||
testGroupVersion := schema.GroupVersion{Group: testGroup, Version: "test"}
|
||||
internalGroupVersion := schema.GroupVersion{Group: testGroup, Version: "test"}
|
||||
|
||||
testCases := []struct {
|
||||
Kind string
|
||||
APIGroupVersions []schema.GroupVersion
|
||||
DefaultVersions []schema.GroupVersion
|
||||
|
||||
Resource string
|
||||
ExpectedGroupVersion *schema.GroupVersion
|
||||
Err bool
|
||||
}{
|
||||
{Kind: "Unknown", Err: true},
|
||||
{Kind: "InternalObject", Err: true},
|
||||
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "Unknown", Err: true},
|
||||
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
|
||||
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
|
||||
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{}, Resource: "internalobjects", ExpectedGroupVersion: &schema.GroupVersion{Group: testGroup, Version: "test"}},
|
||||
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
|
||||
|
||||
// TODO: add test for a resource that exists in one version but not another
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper(testCase.DefaultVersions, fakeInterfaces)
|
||||
mapper.Add(internalGroupVersion.WithKind("InternalObject"), RESTScopeNamespace)
|
||||
|
||||
preferredVersions := []string{}
|
||||
for _, gv := range testCase.APIGroupVersions {
|
||||
preferredVersions = append(preferredVersions, gv.Version)
|
||||
}
|
||||
gk := schema.GroupKind{Group: testGroup, Kind: testCase.Kind}
|
||||
|
||||
mapping, err := mapper.RESTMapping(gk, preferredVersions...)
|
||||
hasErr := err != nil
|
||||
if hasErr != testCase.Err {
|
||||
t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err)
|
||||
}
|
||||
if hasErr {
|
||||
continue
|
||||
}
|
||||
if mapping.Resource != testCase.Resource {
|
||||
t.Errorf("%d: unexpected resource: %#v", i, mapping)
|
||||
}
|
||||
|
||||
if mapping.MetadataAccessor == nil || mapping.ObjectConvertor == nil {
|
||||
t.Errorf("%d: missing codec and accessor: %#v", i, mapping)
|
||||
}
|
||||
|
||||
groupVersion := testCase.ExpectedGroupVersion
|
||||
if groupVersion == nil {
|
||||
groupVersion = &testCase.APIGroupVersions[0]
|
||||
}
|
||||
if mapping.GroupVersionKind.GroupVersion() != *groupVersion {
|
||||
t.Errorf("%d: unexpected version: %#v", i, mapping)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
|
||||
expectedGroupVersion1 := schema.GroupVersion{Group: "tgroup", Version: "test1"}
|
||||
expectedGroupVersion2 := schema.GroupVersion{Group: "tgroup", Version: "test2"}
|
||||
expectedGroupVersion3 := schema.GroupVersion{Group: "tgroup", Version: "test3"}
|
||||
internalObjectGK := schema.GroupKind{Group: "tgroup", Kind: "InternalObject"}
|
||||
otherObjectGK := schema.GroupKind{Group: "tgroup", Kind: "OtherObject"}
|
||||
|
||||
mapper := NewDefaultRESTMapper([]schema.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}, fakeInterfaces)
|
||||
mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace)
|
||||
mapper.Add(expectedGroupVersion2.WithKind("OtherObject"), RESTScopeNamespace)
|
||||
|
||||
// pick default matching object kind based on search order
|
||||
mapping, err := mapper.RESTMapping(otherObjectGK)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if mapping.Resource != "otherobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 {
|
||||
t.Errorf("unexpected mapping: %#v", mapping)
|
||||
}
|
||||
|
||||
mapping, err = mapper.RESTMapping(internalObjectGK)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if mapping.Resource != "internalobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion1 {
|
||||
t.Errorf("unexpected mapping: %#v", mapping)
|
||||
}
|
||||
|
||||
// mismatch of version
|
||||
mapping, err = mapper.RESTMapping(internalObjectGK, expectedGroupVersion2.Version)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion1.Version)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
|
||||
// not in the search versions
|
||||
mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
|
||||
// explicit search order
|
||||
mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version, expectedGroupVersion1.Version)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
|
||||
mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version, expectedGroupVersion2.Version)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if mapping.Resource != "otherobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 {
|
||||
t.Errorf("unexpected mapping: %#v", mapping)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperRESTMappings(t *testing.T) {
|
||||
testGroup := "tgroup"
|
||||
testGroupVersion := schema.GroupVersion{Group: testGroup, Version: "v1"}
|
||||
|
||||
testCases := []struct {
|
||||
Kind string
|
||||
APIGroupVersions []schema.GroupVersion
|
||||
DefaultVersions []schema.GroupVersion
|
||||
AddGroupVersionKind []schema.GroupVersionKind
|
||||
|
||||
ExpectedRESTMappings []*RESTMapping
|
||||
Err bool
|
||||
}{
|
||||
{Kind: "Unknown", Err: true},
|
||||
{Kind: "InternalObject", Err: true},
|
||||
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "Unknown", Err: true},
|
||||
|
||||
// ask for specific version - not available - thus error
|
||||
{DefaultVersions: []schema.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "v2"}}, Err: true},
|
||||
|
||||
// ask for specific version - available - check ExpectedRESTMappings
|
||||
{
|
||||
DefaultVersions: []schema.GroupVersion{testGroupVersion},
|
||||
Kind: "InternalObject",
|
||||
APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "v2"}},
|
||||
AddGroupVersionKind: []schema.GroupVersionKind{schema.GroupVersion{Group: testGroup, Version: "v2"}.WithKind("InternalObject")},
|
||||
ExpectedRESTMappings: []*RESTMapping{{Resource: "internalobjects", GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}}},
|
||||
},
|
||||
|
||||
// ask for specific versions - only one available - check ExpectedRESTMappings
|
||||
{
|
||||
DefaultVersions: []schema.GroupVersion{testGroupVersion},
|
||||
Kind: "InternalObject",
|
||||
APIGroupVersions: []schema.GroupVersion{{Group: testGroup, Version: "v3"}, {Group: testGroup, Version: "v2"}},
|
||||
AddGroupVersionKind: []schema.GroupVersionKind{schema.GroupVersion{Group: testGroup, Version: "v2"}.WithKind("InternalObject")},
|
||||
ExpectedRESTMappings: []*RESTMapping{{Resource: "internalobjects", GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}}},
|
||||
},
|
||||
|
||||
// do not ask for specific version - search through default versions - check ExpectedRESTMappings
|
||||
{
|
||||
DefaultVersions: []schema.GroupVersion{testGroupVersion, {Group: testGroup, Version: "v2"}},
|
||||
Kind: "InternalObject",
|
||||
AddGroupVersionKind: []schema.GroupVersionKind{schema.GroupVersion{Group: testGroup, Version: "v1"}.WithKind("InternalObject"), schema.GroupVersion{Group: testGroup, Version: "v2"}.WithKind("InternalObject")},
|
||||
ExpectedRESTMappings: []*RESTMapping{{Resource: "internalobjects", GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v1", Kind: "InternalObject"}}, {Resource: "internalobjects", GroupVersionKind: schema.GroupVersionKind{Group: testGroup, Version: "v2", Kind: "InternalObject"}}},
|
||||
},
|
||||
}
|
||||
|
||||
for i, testCase := range testCases {
|
||||
mapper := NewDefaultRESTMapper(testCase.DefaultVersions, fakeInterfaces)
|
||||
for _, gvk := range testCase.AddGroupVersionKind {
|
||||
mapper.Add(gvk, RESTScopeNamespace)
|
||||
}
|
||||
|
||||
preferredVersions := []string{}
|
||||
for _, gv := range testCase.APIGroupVersions {
|
||||
preferredVersions = append(preferredVersions, gv.Version)
|
||||
}
|
||||
gk := schema.GroupKind{Group: testGroup, Kind: testCase.Kind}
|
||||
|
||||
mappings, err := mapper.RESTMappings(gk, preferredVersions...)
|
||||
hasErr := err != nil
|
||||
if hasErr != testCase.Err {
|
||||
t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err)
|
||||
}
|
||||
if hasErr {
|
||||
continue
|
||||
}
|
||||
if len(mappings) != len(testCase.ExpectedRESTMappings) {
|
||||
t.Errorf("%d: unexpected number = %d of rest mappings was returned, expected = %d", i, len(mappings), len(testCase.ExpectedRESTMappings))
|
||||
}
|
||||
for j, mapping := range mappings {
|
||||
exp := testCase.ExpectedRESTMappings[j]
|
||||
if mapping.Resource != exp.Resource {
|
||||
t.Errorf("%d - %d: unexpected resource: %#v", i, j, mapping)
|
||||
}
|
||||
if mapping.MetadataAccessor == nil || mapping.ObjectConvertor == nil {
|
||||
t.Errorf("%d - %d: missing codec and accessor: %#v", i, j, mapping)
|
||||
}
|
||||
if mapping.GroupVersionKind != exp.GroupVersionKind {
|
||||
t.Errorf("%d - %d: unexpected GroupVersionKind: %#v", i, j, mapping)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTMapperReportsErrorOnBadVersion(t *testing.T) {
|
||||
expectedGroupVersion1 := schema.GroupVersion{Group: "tgroup", Version: "test1"}
|
||||
expectedGroupVersion2 := schema.GroupVersion{Group: "tgroup", Version: "test2"}
|
||||
internalObjectGK := schema.GroupKind{Group: "tgroup", Kind: "InternalObject"}
|
||||
|
||||
mapper := NewDefaultRESTMapper([]schema.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}, unmatchedVersionInterfaces)
|
||||
mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace)
|
||||
_, err := mapper.RESTMapping(internalObjectGK, expectedGroupVersion1.Version)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
}
|
47
vendor/k8s.io/apimachinery/pkg/api/meta/unstructured.go
generated
vendored
Normal file
47
vendor/k8s.io/apimachinery/pkg/api/meta/unstructured.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2016 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 meta
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// InterfacesForUnstructuredConversion returns VersionInterfaces suitable for
|
||||
// dealing with unstructured.Unstructured objects and supports conversion
|
||||
// from typed objects (provided by parent) to untyped objects.
|
||||
func InterfacesForUnstructuredConversion(parent VersionInterfacesFunc) VersionInterfacesFunc {
|
||||
return func(version schema.GroupVersion) (*VersionInterfaces, error) {
|
||||
if i, err := parent(version); err == nil {
|
||||
return &VersionInterfaces{
|
||||
ObjectConvertor: i.ObjectConvertor,
|
||||
MetadataAccessor: NewAccessor(),
|
||||
}, nil
|
||||
}
|
||||
return InterfacesForUnstructured(version)
|
||||
}
|
||||
}
|
||||
|
||||
// InterfacesForUnstructured returns VersionInterfaces suitable for
|
||||
// dealing with unstructured.Unstructured objects. It will return errors for
|
||||
// other conversions.
|
||||
func InterfacesForUnstructured(schema.GroupVersion) (*VersionInterfaces, error) {
|
||||
return &VersionInterfaces{
|
||||
ObjectConvertor: &unstructured.UnstructuredObjectConverter{},
|
||||
MetadataAccessor: NewAccessor(),
|
||||
}, nil
|
||||
}
|
73
vendor/k8s.io/apimachinery/pkg/api/resource/BUILD
generated
vendored
Normal file
73
vendor/k8s.io/apimachinery/pkg/api/resource/BUILD
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"amount_test.go",
|
||||
"math_test.go",
|
||||
"quantity_proto_test.go",
|
||||
"quantity_test.go",
|
||||
"scale_int_test.go",
|
||||
],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/resource",
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/gopkg.in/inf.v0:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"amount.go",
|
||||
"generated.pb.go",
|
||||
"math.go",
|
||||
"quantity.go",
|
||||
"quantity_proto.go",
|
||||
"scale_int.go",
|
||||
"suffix.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/resource",
|
||||
deps = [
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/gopkg.in/inf.v0:go_default_library",
|
||||
"//vendor/k8s.io/kube-openapi/pkg/common:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_xtest",
|
||||
srcs = ["quantity_example_test.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/resource_test",
|
||||
deps = ["//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "go_default_library_protos",
|
||||
srcs = ["generated.proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
17
vendor/k8s.io/apimachinery/pkg/api/resource/OWNERS
generated
vendored
Executable file
17
vendor/k8s.io/apimachinery/pkg/api/resource/OWNERS
generated
vendored
Executable file
@ -0,0 +1,17 @@
|
||||
reviewers:
|
||||
- thockin
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- derekwaynecarr
|
||||
- mikedanese
|
||||
- saad-ali
|
||||
- janetkuo
|
||||
- tallclair
|
||||
- eparis
|
||||
- timothysc
|
||||
- jbeda
|
||||
- xiang90
|
||||
- mbohlool
|
||||
- david-mcmahon
|
||||
- goltermann
|
299
vendor/k8s.io/apimachinery/pkg/api/resource/amount.go
generated
vendored
Normal file
299
vendor/k8s.io/apimachinery/pkg/api/resource/amount.go
generated
vendored
Normal file
@ -0,0 +1,299 @@
|
||||
/*
|
||||
Copyright 2014 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 resource
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"strconv"
|
||||
|
||||
inf "gopkg.in/inf.v0"
|
||||
)
|
||||
|
||||
// Scale is used for getting and setting the base-10 scaled value.
|
||||
// Base-2 scales are omitted for mathematical simplicity.
|
||||
// See Quantity.ScaledValue for more details.
|
||||
type Scale int32
|
||||
|
||||
// infScale adapts a Scale value to an inf.Scale value.
|
||||
func (s Scale) infScale() inf.Scale {
|
||||
return inf.Scale(-s) // inf.Scale is upside-down
|
||||
}
|
||||
|
||||
const (
|
||||
Nano Scale = -9
|
||||
Micro Scale = -6
|
||||
Milli Scale = -3
|
||||
Kilo Scale = 3
|
||||
Mega Scale = 6
|
||||
Giga Scale = 9
|
||||
Tera Scale = 12
|
||||
Peta Scale = 15
|
||||
Exa Scale = 18
|
||||
)
|
||||
|
||||
var (
|
||||
Zero = int64Amount{}
|
||||
|
||||
// Used by quantity strings - treat as read only
|
||||
zeroBytes = []byte("0")
|
||||
)
|
||||
|
||||
// int64Amount represents a fixed precision numerator and arbitrary scale exponent. It is faster
|
||||
// than operations on inf.Dec for values that can be represented as int64.
|
||||
// +k8s:openapi-gen=true
|
||||
type int64Amount struct {
|
||||
value int64
|
||||
scale Scale
|
||||
}
|
||||
|
||||
// Sign returns 0 if the value is zero, -1 if it is less than 0, or 1 if it is greater than 0.
|
||||
func (a int64Amount) Sign() int {
|
||||
switch {
|
||||
case a.value == 0:
|
||||
return 0
|
||||
case a.value > 0:
|
||||
return 1
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
// AsInt64 returns the current amount as an int64 at scale 0, or false if the value cannot be
|
||||
// represented in an int64 OR would result in a loss of precision. This method is intended as
|
||||
// an optimization to avoid calling AsDec.
|
||||
func (a int64Amount) AsInt64() (int64, bool) {
|
||||
if a.scale == 0 {
|
||||
return a.value, true
|
||||
}
|
||||
if a.scale < 0 {
|
||||
// TODO: attempt to reduce factors, although it is assumed that factors are reduced prior
|
||||
// to the int64Amount being created.
|
||||
return 0, false
|
||||
}
|
||||
return positiveScaleInt64(a.value, a.scale)
|
||||
}
|
||||
|
||||
// AsScaledInt64 returns an int64 representing the value of this amount at the specified scale,
|
||||
// rounding up, or false if that would result in overflow. (1e20).AsScaledInt64(1) would result
|
||||
// in overflow because 1e19 is not representable as an int64. Note that setting a scale larger
|
||||
// than the current value may result in loss of precision - i.e. (1e-6).AsScaledInt64(0) would
|
||||
// return 1, because 0.000001 is rounded up to 1.
|
||||
func (a int64Amount) AsScaledInt64(scale Scale) (result int64, ok bool) {
|
||||
if a.scale < scale {
|
||||
result, _ = negativeScaleInt64(a.value, scale-a.scale)
|
||||
return result, true
|
||||
}
|
||||
return positiveScaleInt64(a.value, a.scale-scale)
|
||||
}
|
||||
|
||||
// AsDec returns an inf.Dec representation of this value.
|
||||
func (a int64Amount) AsDec() *inf.Dec {
|
||||
var base inf.Dec
|
||||
base.SetUnscaled(a.value)
|
||||
base.SetScale(inf.Scale(-a.scale))
|
||||
return &base
|
||||
}
|
||||
|
||||
// Cmp returns 0 if a and b are equal, 1 if a is greater than b, or -1 if a is less than b.
|
||||
func (a int64Amount) Cmp(b int64Amount) int {
|
||||
switch {
|
||||
case a.scale == b.scale:
|
||||
// compare only the unscaled portion
|
||||
case a.scale > b.scale:
|
||||
result, remainder, exact := divideByScaleInt64(b.value, a.scale-b.scale)
|
||||
if !exact {
|
||||
return a.AsDec().Cmp(b.AsDec())
|
||||
}
|
||||
if result == a.value {
|
||||
switch {
|
||||
case remainder == 0:
|
||||
return 0
|
||||
case remainder > 0:
|
||||
return -1
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
b.value = result
|
||||
default:
|
||||
result, remainder, exact := divideByScaleInt64(a.value, b.scale-a.scale)
|
||||
if !exact {
|
||||
return a.AsDec().Cmp(b.AsDec())
|
||||
}
|
||||
if result == b.value {
|
||||
switch {
|
||||
case remainder == 0:
|
||||
return 0
|
||||
case remainder > 0:
|
||||
return 1
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
}
|
||||
a.value = result
|
||||
}
|
||||
|
||||
switch {
|
||||
case a.value == b.value:
|
||||
return 0
|
||||
case a.value < b.value:
|
||||
return -1
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// Add adds two int64Amounts together, matching scales. It will return false and not mutate
|
||||
// a if overflow or underflow would result.
|
||||
func (a *int64Amount) Add(b int64Amount) bool {
|
||||
switch {
|
||||
case b.value == 0:
|
||||
return true
|
||||
case a.value == 0:
|
||||
a.value = b.value
|
||||
a.scale = b.scale
|
||||
return true
|
||||
case a.scale == b.scale:
|
||||
c, ok := int64Add(a.value, b.value)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
a.value = c
|
||||
case a.scale > b.scale:
|
||||
c, ok := positiveScaleInt64(a.value, a.scale-b.scale)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
c, ok = int64Add(c, b.value)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
a.scale = b.scale
|
||||
a.value = c
|
||||
default:
|
||||
c, ok := positiveScaleInt64(b.value, b.scale-a.scale)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
c, ok = int64Add(a.value, c)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
a.value = c
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Sub removes the value of b from the current amount, or returns false if underflow would result.
|
||||
func (a *int64Amount) Sub(b int64Amount) bool {
|
||||
return a.Add(int64Amount{value: -b.value, scale: b.scale})
|
||||
}
|
||||
|
||||
// AsScale adjusts this amount to set a minimum scale, rounding up, and returns true iff no precision
|
||||
// was lost. (1.1e5).AsScale(5) would return 1.1e5, but (1.1e5).AsScale(6) would return 1e6.
|
||||
func (a int64Amount) AsScale(scale Scale) (int64Amount, bool) {
|
||||
if a.scale >= scale {
|
||||
return a, true
|
||||
}
|
||||
result, exact := negativeScaleInt64(a.value, scale-a.scale)
|
||||
return int64Amount{value: result, scale: scale}, exact
|
||||
}
|
||||
|
||||
// AsCanonicalBytes accepts a buffer to write the base-10 string value of this field to, and returns
|
||||
// either that buffer or a larger buffer and the current exponent of the value. The value is adjusted
|
||||
// until the exponent is a multiple of 3 - i.e. 1.1e5 would return "110", 3.
|
||||
func (a int64Amount) AsCanonicalBytes(out []byte) (result []byte, exponent int32) {
|
||||
mantissa := a.value
|
||||
exponent = int32(a.scale)
|
||||
|
||||
amount, times := removeInt64Factors(mantissa, 10)
|
||||
exponent += int32(times)
|
||||
|
||||
// make sure exponent is a multiple of 3
|
||||
var ok bool
|
||||
switch exponent % 3 {
|
||||
case 1, -2:
|
||||
amount, ok = int64MultiplyScale10(amount)
|
||||
if !ok {
|
||||
return infDecAmount{a.AsDec()}.AsCanonicalBytes(out)
|
||||
}
|
||||
exponent = exponent - 1
|
||||
case 2, -1:
|
||||
amount, ok = int64MultiplyScale100(amount)
|
||||
if !ok {
|
||||
return infDecAmount{a.AsDec()}.AsCanonicalBytes(out)
|
||||
}
|
||||
exponent = exponent - 2
|
||||
}
|
||||
return strconv.AppendInt(out, amount, 10), exponent
|
||||
}
|
||||
|
||||
// AsCanonicalBase1024Bytes accepts a buffer to write the base-1024 string value of this field to, and returns
|
||||
// either that buffer or a larger buffer and the current exponent of the value. 2048 is 2 * 1024 ^ 1 and would
|
||||
// return []byte("2048"), 1.
|
||||
func (a int64Amount) AsCanonicalBase1024Bytes(out []byte) (result []byte, exponent int32) {
|
||||
value, ok := a.AsScaledInt64(0)
|
||||
if !ok {
|
||||
return infDecAmount{a.AsDec()}.AsCanonicalBase1024Bytes(out)
|
||||
}
|
||||
amount, exponent := removeInt64Factors(value, 1024)
|
||||
return strconv.AppendInt(out, amount, 10), exponent
|
||||
}
|
||||
|
||||
// infDecAmount implements common operations over an inf.Dec that are specific to the quantity
|
||||
// representation.
|
||||
type infDecAmount struct {
|
||||
*inf.Dec
|
||||
}
|
||||
|
||||
// AsScale adjusts this amount to set a minimum scale, rounding up, and returns true iff no precision
|
||||
// was lost. (1.1e5).AsScale(5) would return 1.1e5, but (1.1e5).AsScale(6) would return 1e6.
|
||||
func (a infDecAmount) AsScale(scale Scale) (infDecAmount, bool) {
|
||||
tmp := &inf.Dec{}
|
||||
tmp.Round(a.Dec, scale.infScale(), inf.RoundUp)
|
||||
return infDecAmount{tmp}, tmp.Cmp(a.Dec) == 0
|
||||
}
|
||||
|
||||
// AsCanonicalBytes accepts a buffer to write the base-10 string value of this field to, and returns
|
||||
// either that buffer or a larger buffer and the current exponent of the value. The value is adjusted
|
||||
// until the exponent is a multiple of 3 - i.e. 1.1e5 would return "110", 3.
|
||||
func (a infDecAmount) AsCanonicalBytes(out []byte) (result []byte, exponent int32) {
|
||||
mantissa := a.Dec.UnscaledBig()
|
||||
exponent = int32(-a.Dec.Scale())
|
||||
amount := big.NewInt(0).Set(mantissa)
|
||||
// move all factors of 10 into the exponent for easy reasoning
|
||||
amount, times := removeBigIntFactors(amount, bigTen)
|
||||
exponent += times
|
||||
|
||||
// make sure exponent is a multiple of 3
|
||||
for exponent%3 != 0 {
|
||||
amount.Mul(amount, bigTen)
|
||||
exponent--
|
||||
}
|
||||
|
||||
return append(out, amount.String()...), exponent
|
||||
}
|
||||
|
||||
// AsCanonicalBase1024Bytes accepts a buffer to write the base-1024 string value of this field to, and returns
|
||||
// either that buffer or a larger buffer and the current exponent of the value. 2048 is 2 * 1024 ^ 1 and would
|
||||
// return []byte("2048"), 1.
|
||||
func (a infDecAmount) AsCanonicalBase1024Bytes(out []byte) (result []byte, exponent int32) {
|
||||
tmp := &inf.Dec{}
|
||||
tmp.Round(a.Dec, 0, inf.RoundUp)
|
||||
amount, exponent := removeBigIntFactors(tmp.UnscaledBig(), big1024)
|
||||
return append(out, amount.String()...), exponent
|
||||
}
|
133
vendor/k8s.io/apimachinery/pkg/api/resource/amount_test.go
generated
vendored
Normal file
133
vendor/k8s.io/apimachinery/pkg/api/resource/amount_test.go
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
Copyright 2014 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 resource
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInt64AmountAsInt64(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
value int64
|
||||
scale Scale
|
||||
result int64
|
||||
ok bool
|
||||
}{
|
||||
{100, 0, 100, true},
|
||||
{100, 1, 1000, true},
|
||||
{100, -5, 0, false},
|
||||
{100, 100, 0, false},
|
||||
} {
|
||||
r, ok := int64Amount{value: test.value, scale: test.scale}.AsInt64()
|
||||
if r != test.result {
|
||||
t.Errorf("%v: unexpected result: %d", test, r)
|
||||
}
|
||||
if ok != test.ok {
|
||||
t.Errorf("%v: unexpected ok: %t", test, ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64AmountAdd(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
a, b, c int64Amount
|
||||
ok bool
|
||||
}{
|
||||
{int64Amount{value: 100, scale: 1}, int64Amount{value: 10, scale: 2}, int64Amount{value: 200, scale: 1}, true},
|
||||
{int64Amount{value: 100, scale: 1}, int64Amount{value: 1, scale: 2}, int64Amount{value: 110, scale: 1}, true},
|
||||
{int64Amount{value: 100, scale: 1}, int64Amount{value: 1, scale: 100}, int64Amount{value: 1, scale: 100}, false},
|
||||
{int64Amount{value: -5, scale: 2}, int64Amount{value: 50, scale: 1}, int64Amount{value: 0, scale: 1}, true},
|
||||
{int64Amount{value: -5, scale: 2}, int64Amount{value: 5, scale: 2}, int64Amount{value: 0, scale: 2}, true},
|
||||
|
||||
{int64Amount{value: mostPositive, scale: -1}, int64Amount{value: 1, scale: -1}, int64Amount{value: 0, scale: -1}, false},
|
||||
{int64Amount{value: mostPositive, scale: -1}, int64Amount{value: 0, scale: -1}, int64Amount{value: mostPositive, scale: -1}, true},
|
||||
{int64Amount{value: mostPositive / 10, scale: 1}, int64Amount{value: 10, scale: 0}, int64Amount{value: mostPositive, scale: -1}, false},
|
||||
} {
|
||||
c := test.a
|
||||
ok := c.Add(test.b)
|
||||
if ok != test.ok {
|
||||
t.Errorf("%v: unexpected ok: %t", test, ok)
|
||||
}
|
||||
if ok {
|
||||
if c != test.c {
|
||||
t.Errorf("%v: unexpected result: %d", test, c)
|
||||
}
|
||||
} else {
|
||||
if c != test.a {
|
||||
t.Errorf("%v: overflow addition mutated source: %d", test, c)
|
||||
}
|
||||
}
|
||||
|
||||
// addition is commutative
|
||||
c = test.b
|
||||
if ok := c.Add(test.a); ok != test.ok {
|
||||
t.Errorf("%v: unexpected ok: %t", test, ok)
|
||||
}
|
||||
if ok {
|
||||
if c != test.c {
|
||||
t.Errorf("%v: unexpected result: %d", test, c)
|
||||
}
|
||||
} else {
|
||||
if c != test.b {
|
||||
t.Errorf("%v: overflow addition mutated source: %d", test, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestInt64AsCanonicalString(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
value int64
|
||||
scale Scale
|
||||
result string
|
||||
exponent int32
|
||||
}{
|
||||
{100, 0, "100", 0},
|
||||
{100, 1, "1", 3},
|
||||
{100, -1, "10", 0},
|
||||
{10800, -10, "1080", -9},
|
||||
} {
|
||||
r, exp := int64Amount{value: test.value, scale: test.scale}.AsCanonicalBytes(nil)
|
||||
if string(r) != test.result {
|
||||
t.Errorf("%v: unexpected result: %s", test, r)
|
||||
}
|
||||
if exp != test.exponent {
|
||||
t.Errorf("%v: unexpected exponent: %d", test, exp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAmountSign(t *testing.T) {
|
||||
table := []struct {
|
||||
i int64Amount
|
||||
expect int
|
||||
}{
|
||||
{int64Amount{value: -50, scale: 1}, -1},
|
||||
{int64Amount{value: 0, scale: 1}, 0},
|
||||
{int64Amount{value: 300, scale: 1}, 1},
|
||||
{int64Amount{value: -50, scale: -8}, -1},
|
||||
{int64Amount{value: 50, scale: -8}, 1},
|
||||
{int64Amount{value: 0, scale: -8}, 0},
|
||||
{int64Amount{value: -50, scale: 0}, -1},
|
||||
{int64Amount{value: 50, scale: 0}, 1},
|
||||
{int64Amount{value: 0, scale: 0}, 0},
|
||||
}
|
||||
for _, testCase := range table {
|
||||
if result := testCase.i.Sign(); result != testCase.expect {
|
||||
t.Errorf("i: %v, Expected: %v, Actual: %v", testCase.i, testCase.expect, result)
|
||||
}
|
||||
}
|
||||
}
|
77
vendor/k8s.io/apimachinery/pkg/api/resource/generated.pb.go
generated
vendored
Normal file
77
vendor/k8s.io/apimachinery/pkg/api/resource/generated.pb.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright 2017 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.
|
||||
*/
|
||||
|
||||
// Code generated by protoc-gen-gogo.
|
||||
// source: k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/api/resource/generated.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package resource is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/api/resource/generated.proto
|
||||
|
||||
It has these top-level messages:
|
||||
Quantity
|
||||
*/
|
||||
package resource
|
||||
|
||||
import proto "github.com/gogo/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
func (m *Quantity) Reset() { *m = Quantity{} }
|
||||
func (*Quantity) ProtoMessage() {}
|
||||
func (*Quantity) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} }
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Quantity)(nil), "k8s.io.apimachinery.pkg.api.resource.Quantity")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/api/resource/generated.proto", fileDescriptorGenerated)
|
||||
}
|
||||
|
||||
var fileDescriptorGenerated = []byte{
|
||||
// 255 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x8f, 0xa1, 0x4e, 0x03, 0x41,
|
||||
0x10, 0x86, 0x77, 0x0d, 0x29, 0x95, 0x0d, 0x21, 0xa4, 0x62, 0xaf, 0x21, 0x08, 0x0c, 0x3b, 0x02,
|
||||
0xd3, 0x20, 0xf1, 0x08, 0x90, 0xb8, 0xbb, 0xeb, 0xb0, 0xdd, 0x1c, 0xdd, 0xbd, 0xcc, 0xce, 0x92,
|
||||
0xd4, 0x55, 0x22, 0x2b, 0x91, 0xbd, 0xb7, 0xa9, 0xac, 0xac, 0x40, 0x70, 0xcb, 0x8b, 0x90, 0x5e,
|
||||
0xdb, 0x84, 0x90, 0xe0, 0xe6, 0xfb, 0x27, 0xdf, 0xe4, 0x9f, 0xfe, 0x43, 0x35, 0x0e, 0xda, 0x7a,
|
||||
0xa8, 0x62, 0x81, 0xe4, 0x90, 0x31, 0xc0, 0x1b, 0xba, 0x89, 0x27, 0x38, 0x2c, 0xf2, 0xda, 0xce,
|
||||
0xf2, 0x72, 0x6a, 0x1d, 0xd2, 0x1c, 0xea, 0xca, 0xec, 0x02, 0x20, 0x0c, 0x3e, 0x52, 0x89, 0x60,
|
||||
0xd0, 0x21, 0xe5, 0x8c, 0x13, 0x5d, 0x93, 0x67, 0x3f, 0xb8, 0xda, 0x5b, 0xfa, 0xb7, 0xa5, 0xeb,
|
||||
0xca, 0xec, 0x02, 0x7d, 0xb4, 0x86, 0x37, 0xc6, 0xf2, 0x34, 0x16, 0xba, 0xf4, 0x33, 0x30, 0xde,
|
||||
0x78, 0xe8, 0xe4, 0x22, 0xbe, 0x74, 0xd4, 0x41, 0x37, 0xed, 0x8f, 0x0e, 0x6f, 0xff, 0xab, 0x12,
|
||||
0xd9, 0xbe, 0x82, 0x75, 0x1c, 0x98, 0xfe, 0x36, 0xb9, 0x1c, 0xf7, 0x7b, 0x8f, 0x31, 0x77, 0x6c,
|
||||
0x79, 0x3e, 0x38, 0xef, 0x9f, 0x04, 0x26, 0xeb, 0xcc, 0x85, 0x1c, 0xc9, 0xeb, 0xd3, 0xa7, 0x03,
|
||||
0xdd, 0x9d, 0x7d, 0xac, 0x32, 0xf1, 0xde, 0x64, 0x62, 0xd9, 0x64, 0x62, 0xd5, 0x64, 0x62, 0xf1,
|
||||
0x39, 0x12, 0xf7, 0x7a, 0xdd, 0x2a, 0xb1, 0x69, 0x95, 0xd8, 0xb6, 0x4a, 0x2c, 0x92, 0x92, 0xeb,
|
||||
0xa4, 0xe4, 0x26, 0x29, 0xb9, 0x4d, 0x4a, 0x7e, 0x25, 0x25, 0x97, 0xdf, 0x4a, 0x3c, 0xf7, 0x8e,
|
||||
0xdf, 0xfc, 0x04, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x5e, 0xda, 0xf9, 0x43, 0x01, 0x00, 0x00,
|
||||
}
|
95
vendor/k8s.io/apimachinery/pkg/api/resource/generated.proto
generated
vendored
Normal file
95
vendor/k8s.io/apimachinery/pkg/api/resource/generated.proto
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright 2017 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.
|
||||
*/
|
||||
|
||||
|
||||
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
|
||||
|
||||
syntax = 'proto2';
|
||||
|
||||
package k8s.io.apimachinery.pkg.api.resource;
|
||||
|
||||
import "k8s.io/apimachinery/pkg/util/intstr/generated.proto";
|
||||
|
||||
// Package-wide variables from generator "generated".
|
||||
option go_package = "resource";
|
||||
|
||||
// Quantity is a fixed-point representation of a number.
|
||||
// It provides convenient marshaling/unmarshaling in JSON and YAML,
|
||||
// in addition to String() and Int64() accessors.
|
||||
//
|
||||
// The serialization format is:
|
||||
//
|
||||
// <quantity> ::= <signedNumber><suffix>
|
||||
// (Note that <suffix> may be empty, from the "" case in <decimalSI>.)
|
||||
// <digit> ::= 0 | 1 | ... | 9
|
||||
// <digits> ::= <digit> | <digit><digits>
|
||||
// <number> ::= <digits> | <digits>.<digits> | <digits>. | .<digits>
|
||||
// <sign> ::= "+" | "-"
|
||||
// <signedNumber> ::= <number> | <sign><number>
|
||||
// <suffix> ::= <binarySI> | <decimalExponent> | <decimalSI>
|
||||
// <binarySI> ::= Ki | Mi | Gi | Ti | Pi | Ei
|
||||
// (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)
|
||||
// <decimalSI> ::= m | "" | k | M | G | T | P | E
|
||||
// (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)
|
||||
// <decimalExponent> ::= "e" <signedNumber> | "E" <signedNumber>
|
||||
//
|
||||
// No matter which of the three exponent forms is used, no quantity may represent
|
||||
// a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal
|
||||
// places. Numbers larger or more precise will be capped or rounded up.
|
||||
// (E.g.: 0.1m will rounded up to 1m.)
|
||||
// This may be extended in the future if we require larger or smaller quantities.
|
||||
//
|
||||
// When a Quantity is parsed from a string, it will remember the type of suffix
|
||||
// it had, and will use the same type again when it is serialized.
|
||||
//
|
||||
// Before serializing, Quantity will be put in "canonical form".
|
||||
// This means that Exponent/suffix will be adjusted up or down (with a
|
||||
// corresponding increase or decrease in Mantissa) such that:
|
||||
// a. No precision is lost
|
||||
// b. No fractional digits will be emitted
|
||||
// c. The exponent (or suffix) is as large as possible.
|
||||
// The sign will be omitted unless the number is negative.
|
||||
//
|
||||
// Examples:
|
||||
// 1.5 will be serialized as "1500m"
|
||||
// 1.5Gi will be serialized as "1536Mi"
|
||||
//
|
||||
// NOTE: We reserve the right to amend this canonical format, perhaps to
|
||||
// allow 1.5 to be canonical.
|
||||
// TODO: Remove above disclaimer after all bikeshedding about format is over,
|
||||
// or after March 2015.
|
||||
//
|
||||
// Note that the quantity will NEVER be internally represented by a
|
||||
// floating point number. That is the whole point of this exercise.
|
||||
//
|
||||
// Non-canonical values will still parse as long as they are well formed,
|
||||
// but will be re-emitted in their canonical form. (So always use canonical
|
||||
// form, or don't diff.)
|
||||
//
|
||||
// This format is intended to make it difficult to use these numbers without
|
||||
// writing some sort of special handling code in the hopes that that will
|
||||
// cause implementors to also use a fixed point implementation.
|
||||
//
|
||||
// +protobuf=true
|
||||
// +protobuf.embed=string
|
||||
// +protobuf.options.marshal=false
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
// +k8s:deepcopy-gen=true
|
||||
// +k8s:openapi-gen=true
|
||||
message Quantity {
|
||||
optional string string = 1;
|
||||
}
|
||||
|
314
vendor/k8s.io/apimachinery/pkg/api/resource/math.go
generated
vendored
Normal file
314
vendor/k8s.io/apimachinery/pkg/api/resource/math.go
generated
vendored
Normal file
@ -0,0 +1,314 @@
|
||||
/*
|
||||
Copyright 2014 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 resource
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
inf "gopkg.in/inf.v0"
|
||||
)
|
||||
|
||||
const (
|
||||
// maxInt64Factors is the highest value that will be checked when removing factors of 10 from an int64.
|
||||
// It is also the maximum decimal digits that can be represented with an int64.
|
||||
maxInt64Factors = 18
|
||||
)
|
||||
|
||||
var (
|
||||
// Commonly needed big.Int values-- treat as read only!
|
||||
bigTen = big.NewInt(10)
|
||||
bigZero = big.NewInt(0)
|
||||
bigOne = big.NewInt(1)
|
||||
bigThousand = big.NewInt(1000)
|
||||
big1024 = big.NewInt(1024)
|
||||
|
||||
// Commonly needed inf.Dec values-- treat as read only!
|
||||
decZero = inf.NewDec(0, 0)
|
||||
decOne = inf.NewDec(1, 0)
|
||||
decMinusOne = inf.NewDec(-1, 0)
|
||||
decThousand = inf.NewDec(1000, 0)
|
||||
dec1024 = inf.NewDec(1024, 0)
|
||||
decMinus1024 = inf.NewDec(-1024, 0)
|
||||
|
||||
// Largest (in magnitude) number allowed.
|
||||
maxAllowed = infDecAmount{inf.NewDec((1<<63)-1, 0)} // == max int64
|
||||
|
||||
// The maximum value we can represent milli-units for.
|
||||
// Compare with the return value of Quantity.Value() to
|
||||
// see if it's safe to use Quantity.MilliValue().
|
||||
MaxMilliValue = int64(((1 << 63) - 1) / 1000)
|
||||
)
|
||||
|
||||
const mostNegative = -(mostPositive + 1)
|
||||
const mostPositive = 1<<63 - 1
|
||||
|
||||
// int64Add returns a+b, or false if that would overflow int64.
|
||||
func int64Add(a, b int64) (int64, bool) {
|
||||
c := a + b
|
||||
switch {
|
||||
case a > 0 && b > 0:
|
||||
if c < 0 {
|
||||
return 0, false
|
||||
}
|
||||
case a < 0 && b < 0:
|
||||
if c > 0 {
|
||||
return 0, false
|
||||
}
|
||||
if a == mostNegative && b == mostNegative {
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
return c, true
|
||||
}
|
||||
|
||||
// int64Multiply returns a*b, or false if that would overflow or underflow int64.
|
||||
func int64Multiply(a, b int64) (int64, bool) {
|
||||
if a == 0 || b == 0 || a == 1 || b == 1 {
|
||||
return a * b, true
|
||||
}
|
||||
if a == mostNegative || b == mostNegative {
|
||||
return 0, false
|
||||
}
|
||||
c := a * b
|
||||
return c, c/b == a
|
||||
}
|
||||
|
||||
// int64MultiplyScale returns a*b, assuming b is greater than one, or false if that would overflow or underflow int64.
|
||||
// Use when b is known to be greater than one.
|
||||
func int64MultiplyScale(a int64, b int64) (int64, bool) {
|
||||
if a == 0 || a == 1 {
|
||||
return a * b, true
|
||||
}
|
||||
if a == mostNegative && b != 1 {
|
||||
return 0, false
|
||||
}
|
||||
c := a * b
|
||||
return c, c/b == a
|
||||
}
|
||||
|
||||
// int64MultiplyScale10 multiplies a by 10, or returns false if that would overflow. This method is faster than
|
||||
// int64Multiply(a, 10) because the compiler can optimize constant factor multiplication.
|
||||
func int64MultiplyScale10(a int64) (int64, bool) {
|
||||
if a == 0 || a == 1 {
|
||||
return a * 10, true
|
||||
}
|
||||
if a == mostNegative {
|
||||
return 0, false
|
||||
}
|
||||
c := a * 10
|
||||
return c, c/10 == a
|
||||
}
|
||||
|
||||
// int64MultiplyScale100 multiplies a by 100, or returns false if that would overflow. This method is faster than
|
||||
// int64Multiply(a, 100) because the compiler can optimize constant factor multiplication.
|
||||
func int64MultiplyScale100(a int64) (int64, bool) {
|
||||
if a == 0 || a == 1 {
|
||||
return a * 100, true
|
||||
}
|
||||
if a == mostNegative {
|
||||
return 0, false
|
||||
}
|
||||
c := a * 100
|
||||
return c, c/100 == a
|
||||
}
|
||||
|
||||
// int64MultiplyScale1000 multiplies a by 1000, or returns false if that would overflow. This method is faster than
|
||||
// int64Multiply(a, 1000) because the compiler can optimize constant factor multiplication.
|
||||
func int64MultiplyScale1000(a int64) (int64, bool) {
|
||||
if a == 0 || a == 1 {
|
||||
return a * 1000, true
|
||||
}
|
||||
if a == mostNegative {
|
||||
return 0, false
|
||||
}
|
||||
c := a * 1000
|
||||
return c, c/1000 == a
|
||||
}
|
||||
|
||||
// positiveScaleInt64 multiplies base by 10^scale, returning false if the
|
||||
// value overflows. Passing a negative scale is undefined.
|
||||
func positiveScaleInt64(base int64, scale Scale) (int64, bool) {
|
||||
switch scale {
|
||||
case 0:
|
||||
return base, true
|
||||
case 1:
|
||||
return int64MultiplyScale10(base)
|
||||
case 2:
|
||||
return int64MultiplyScale100(base)
|
||||
case 3:
|
||||
return int64MultiplyScale1000(base)
|
||||
case 6:
|
||||
return int64MultiplyScale(base, 1000000)
|
||||
case 9:
|
||||
return int64MultiplyScale(base, 1000000000)
|
||||
default:
|
||||
value := base
|
||||
var ok bool
|
||||
for i := Scale(0); i < scale; i++ {
|
||||
if value, ok = int64MultiplyScale(value, 10); !ok {
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
return value, true
|
||||
}
|
||||
}
|
||||
|
||||
// negativeScaleInt64 reduces base by the provided scale, rounding up, until the
|
||||
// value is zero or the scale is reached. Passing a negative scale is undefined.
|
||||
// The value returned, if not exact, is rounded away from zero.
|
||||
func negativeScaleInt64(base int64, scale Scale) (result int64, exact bool) {
|
||||
if scale == 0 {
|
||||
return base, true
|
||||
}
|
||||
|
||||
value := base
|
||||
var fraction bool
|
||||
for i := Scale(0); i < scale; i++ {
|
||||
if !fraction && value%10 != 0 {
|
||||
fraction = true
|
||||
}
|
||||
value = value / 10
|
||||
if value == 0 {
|
||||
if fraction {
|
||||
if base > 0 {
|
||||
return 1, false
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
return 0, true
|
||||
}
|
||||
}
|
||||
if fraction {
|
||||
if base > 0 {
|
||||
value += 1
|
||||
} else {
|
||||
value += -1
|
||||
}
|
||||
}
|
||||
return value, !fraction
|
||||
}
|
||||
|
||||
func pow10Int64(b int64) int64 {
|
||||
switch b {
|
||||
case 0:
|
||||
return 1
|
||||
case 1:
|
||||
return 10
|
||||
case 2:
|
||||
return 100
|
||||
case 3:
|
||||
return 1000
|
||||
case 4:
|
||||
return 10000
|
||||
case 5:
|
||||
return 100000
|
||||
case 6:
|
||||
return 1000000
|
||||
case 7:
|
||||
return 10000000
|
||||
case 8:
|
||||
return 100000000
|
||||
case 9:
|
||||
return 1000000000
|
||||
case 10:
|
||||
return 10000000000
|
||||
case 11:
|
||||
return 100000000000
|
||||
case 12:
|
||||
return 1000000000000
|
||||
case 13:
|
||||
return 10000000000000
|
||||
case 14:
|
||||
return 100000000000000
|
||||
case 15:
|
||||
return 1000000000000000
|
||||
case 16:
|
||||
return 10000000000000000
|
||||
case 17:
|
||||
return 100000000000000000
|
||||
case 18:
|
||||
return 1000000000000000000
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// negativeScaleInt64 returns the result of dividing base by scale * 10 and the remainder, or
|
||||
// false if no such division is possible. Dividing by negative scales is undefined.
|
||||
func divideByScaleInt64(base int64, scale Scale) (result, remainder int64, exact bool) {
|
||||
if scale == 0 {
|
||||
return base, 0, true
|
||||
}
|
||||
// the max scale representable in base 10 in an int64 is 18 decimal places
|
||||
if scale >= 18 {
|
||||
return 0, base, false
|
||||
}
|
||||
divisor := pow10Int64(int64(scale))
|
||||
return base / divisor, base % divisor, true
|
||||
}
|
||||
|
||||
// removeInt64Factors divides in a loop; the return values have the property that
|
||||
// value == result * base ^ scale
|
||||
func removeInt64Factors(value int64, base int64) (result int64, times int32) {
|
||||
times = 0
|
||||
result = value
|
||||
negative := result < 0
|
||||
if negative {
|
||||
result = -result
|
||||
}
|
||||
switch base {
|
||||
// allow the compiler to optimize the common cases
|
||||
case 10:
|
||||
for result >= 10 && result%10 == 0 {
|
||||
times++
|
||||
result = result / 10
|
||||
}
|
||||
// allow the compiler to optimize the common cases
|
||||
case 1024:
|
||||
for result >= 1024 && result%1024 == 0 {
|
||||
times++
|
||||
result = result / 1024
|
||||
}
|
||||
default:
|
||||
for result >= base && result%base == 0 {
|
||||
times++
|
||||
result = result / base
|
||||
}
|
||||
}
|
||||
if negative {
|
||||
result = -result
|
||||
}
|
||||
return result, times
|
||||
}
|
||||
|
||||
// removeBigIntFactors divides in a loop; the return values have the property that
|
||||
// d == result * factor ^ times
|
||||
// d may be modified in place.
|
||||
// If d == 0, then the return values will be (0, 0)
|
||||
func removeBigIntFactors(d, factor *big.Int) (result *big.Int, times int32) {
|
||||
q := big.NewInt(0)
|
||||
m := big.NewInt(0)
|
||||
for d.Cmp(bigZero) != 0 {
|
||||
q.DivMod(d, factor, m)
|
||||
if m.Cmp(bigZero) != 0 {
|
||||
break
|
||||
}
|
||||
times++
|
||||
d, q = q, d
|
||||
}
|
||||
return d, times
|
||||
}
|
211
vendor/k8s.io/apimachinery/pkg/api/resource/math_test.go
generated
vendored
Normal file
211
vendor/k8s.io/apimachinery/pkg/api/resource/math_test.go
generated
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
Copyright 2014 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 resource
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDetectOverflowAdd(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
a, b int64
|
||||
c int64
|
||||
ok bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{-1, 1, 0, true},
|
||||
{0, 1, 1, true},
|
||||
{2, 2, 4, true},
|
||||
{2, -2, 0, true},
|
||||
{-2, -2, -4, true},
|
||||
|
||||
{mostNegative, -1, 0, false},
|
||||
{mostNegative, 1, mostNegative + 1, true},
|
||||
{mostPositive, -1, mostPositive - 1, true},
|
||||
{mostPositive, 1, 0, false},
|
||||
|
||||
{mostNegative, mostPositive, -1, true},
|
||||
{mostPositive, mostNegative, -1, true},
|
||||
{mostPositive, mostPositive, 0, false},
|
||||
{mostNegative, mostNegative, 0, false},
|
||||
|
||||
{-mostPositive, mostNegative, 0, false},
|
||||
{mostNegative, -mostPositive, 0, false},
|
||||
{-mostPositive, -mostPositive, 0, false},
|
||||
} {
|
||||
c, ok := int64Add(test.a, test.b)
|
||||
if c != test.c {
|
||||
t.Errorf("%v: unexpected result: %d", test, c)
|
||||
}
|
||||
if ok != test.ok {
|
||||
t.Errorf("%v: unexpected overflow: %t", test, ok)
|
||||
}
|
||||
// addition is commutative
|
||||
d, ok2 := int64Add(test.b, test.a)
|
||||
if c != d || ok != ok2 {
|
||||
t.Errorf("%v: not commutative: %d %t", test, d, ok2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectOverflowMultiply(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
a, b int64
|
||||
c int64
|
||||
ok bool
|
||||
}{
|
||||
{0, 0, 0, true},
|
||||
{-1, 1, -1, true},
|
||||
{-1, -1, 1, true},
|
||||
{1, 1, 1, true},
|
||||
{0, 1, 0, true},
|
||||
{1, 0, 0, true},
|
||||
{2, 2, 4, true},
|
||||
{2, -2, -4, true},
|
||||
{-2, -2, 4, true},
|
||||
|
||||
{mostNegative, -1, 0, false},
|
||||
{mostNegative, 1, mostNegative, true},
|
||||
{mostPositive, -1, -mostPositive, true},
|
||||
{mostPositive, 1, mostPositive, true},
|
||||
|
||||
{mostNegative, mostPositive, 0, false},
|
||||
{mostPositive, mostNegative, 0, false},
|
||||
{mostPositive, mostPositive, 1, false},
|
||||
{mostNegative, mostNegative, 0, false},
|
||||
|
||||
{-mostPositive, mostNegative, 0, false},
|
||||
{mostNegative, -mostPositive, 0, false},
|
||||
{-mostPositive, -mostPositive, 1, false},
|
||||
} {
|
||||
c, ok := int64Multiply(test.a, test.b)
|
||||
if c != test.c {
|
||||
t.Errorf("%v: unexpected result: %d", test, c)
|
||||
}
|
||||
if ok != test.ok {
|
||||
t.Errorf("%v: unexpected overflow: %t", test, ok)
|
||||
}
|
||||
// multiplication is commutative
|
||||
d, ok2 := int64Multiply(test.b, test.a)
|
||||
if c != d || ok != ok2 {
|
||||
t.Errorf("%v: not commutative: %d %t", test, d, ok2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectOverflowScale(t *testing.T) {
|
||||
for _, a := range []int64{0, -1, 1, 10, -10, mostPositive, mostNegative, -mostPositive} {
|
||||
for _, b := range []int64{1, 2, 10, 100, 1000, mostPositive} {
|
||||
expect, expectOk := int64Multiply(a, b)
|
||||
|
||||
c, ok := int64MultiplyScale(a, b)
|
||||
if c != expect {
|
||||
t.Errorf("%d*%d: unexpected result: %d", a, b, c)
|
||||
}
|
||||
if ok != expectOk {
|
||||
t.Errorf("%d*%d: unexpected overflow: %t", a, b, ok)
|
||||
}
|
||||
}
|
||||
for _, test := range []struct {
|
||||
base int64
|
||||
fn func(a int64) (int64, bool)
|
||||
}{
|
||||
{10, int64MultiplyScale10},
|
||||
{100, int64MultiplyScale100},
|
||||
{1000, int64MultiplyScale1000},
|
||||
} {
|
||||
expect, expectOk := int64Multiply(a, test.base)
|
||||
c, ok := test.fn(a)
|
||||
if c != expect {
|
||||
t.Errorf("%d*%d: unexpected result: %d", a, test.base, c)
|
||||
}
|
||||
if ok != expectOk {
|
||||
t.Errorf("%d*%d: unexpected overflow: %t", a, test.base, ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveInt64Factors(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
value int64
|
||||
max int64
|
||||
result int64
|
||||
scale int32
|
||||
}{
|
||||
{100, 10, 1, 2},
|
||||
{100, 10, 1, 2},
|
||||
{100, 100, 1, 1},
|
||||
{1, 10, 1, 0},
|
||||
} {
|
||||
r, s := removeInt64Factors(test.value, test.max)
|
||||
if r != test.result {
|
||||
t.Errorf("%v: unexpected result: %d", test, r)
|
||||
}
|
||||
if s != test.scale {
|
||||
t.Errorf("%v: unexpected scale: %d", test, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNegativeScaleInt64(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
base int64
|
||||
scale Scale
|
||||
result int64
|
||||
exact bool
|
||||
}{
|
||||
{1234567, 0, 1234567, true},
|
||||
{1234567, 1, 123457, false},
|
||||
{1234567, 2, 12346, false},
|
||||
{1234567, 3, 1235, false},
|
||||
{1234567, 4, 124, false},
|
||||
|
||||
{-1234567, 0, -1234567, true},
|
||||
{-1234567, 1, -123457, false},
|
||||
{-1234567, 2, -12346, false},
|
||||
{-1234567, 3, -1235, false},
|
||||
{-1234567, 4, -124, false},
|
||||
|
||||
{1000, 0, 1000, true},
|
||||
{1000, 1, 100, true},
|
||||
{1000, 2, 10, true},
|
||||
{1000, 3, 1, true},
|
||||
{1000, 4, 1, false},
|
||||
|
||||
{-1000, 0, -1000, true},
|
||||
{-1000, 1, -100, true},
|
||||
{-1000, 2, -10, true},
|
||||
{-1000, 3, -1, true},
|
||||
{-1000, 4, -1, false},
|
||||
|
||||
{0, 0, 0, true},
|
||||
{0, 1, 0, true},
|
||||
{0, 2, 0, true},
|
||||
|
||||
// negative scale is undefined behavior
|
||||
{1000, -1, 1000, true},
|
||||
} {
|
||||
result, exact := negativeScaleInt64(test.base, test.scale)
|
||||
if result != test.result {
|
||||
t.Errorf("%v: unexpected result: %d", test, result)
|
||||
}
|
||||
if exact != test.exact {
|
||||
t.Errorf("%v: unexpected exact: %t", test, exact)
|
||||
}
|
||||
}
|
||||
}
|
793
vendor/k8s.io/apimachinery/pkg/api/resource/quantity.go
generated
vendored
Normal file
793
vendor/k8s.io/apimachinery/pkg/api/resource/quantity.go
generated
vendored
Normal file
@ -0,0 +1,793 @@
|
||||
/*
|
||||
Copyright 2014 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 resource
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
inf "gopkg.in/inf.v0"
|
||||
openapi "k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
// Quantity is a fixed-point representation of a number.
|
||||
// It provides convenient marshaling/unmarshaling in JSON and YAML,
|
||||
// in addition to String() and Int64() accessors.
|
||||
//
|
||||
// The serialization format is:
|
||||
//
|
||||
// <quantity> ::= <signedNumber><suffix>
|
||||
// (Note that <suffix> may be empty, from the "" case in <decimalSI>.)
|
||||
// <digit> ::= 0 | 1 | ... | 9
|
||||
// <digits> ::= <digit> | <digit><digits>
|
||||
// <number> ::= <digits> | <digits>.<digits> | <digits>. | .<digits>
|
||||
// <sign> ::= "+" | "-"
|
||||
// <signedNumber> ::= <number> | <sign><number>
|
||||
// <suffix> ::= <binarySI> | <decimalExponent> | <decimalSI>
|
||||
// <binarySI> ::= Ki | Mi | Gi | Ti | Pi | Ei
|
||||
// (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)
|
||||
// <decimalSI> ::= m | "" | k | M | G | T | P | E
|
||||
// (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)
|
||||
// <decimalExponent> ::= "e" <signedNumber> | "E" <signedNumber>
|
||||
//
|
||||
// No matter which of the three exponent forms is used, no quantity may represent
|
||||
// a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal
|
||||
// places. Numbers larger or more precise will be capped or rounded up.
|
||||
// (E.g.: 0.1m will rounded up to 1m.)
|
||||
// This may be extended in the future if we require larger or smaller quantities.
|
||||
//
|
||||
// When a Quantity is parsed from a string, it will remember the type of suffix
|
||||
// it had, and will use the same type again when it is serialized.
|
||||
//
|
||||
// Before serializing, Quantity will be put in "canonical form".
|
||||
// This means that Exponent/suffix will be adjusted up or down (with a
|
||||
// corresponding increase or decrease in Mantissa) such that:
|
||||
// a. No precision is lost
|
||||
// b. No fractional digits will be emitted
|
||||
// c. The exponent (or suffix) is as large as possible.
|
||||
// The sign will be omitted unless the number is negative.
|
||||
//
|
||||
// Examples:
|
||||
// 1.5 will be serialized as "1500m"
|
||||
// 1.5Gi will be serialized as "1536Mi"
|
||||
//
|
||||
// NOTE: We reserve the right to amend this canonical format, perhaps to
|
||||
// allow 1.5 to be canonical.
|
||||
// TODO: Remove above disclaimer after all bikeshedding about format is over,
|
||||
// or after March 2015.
|
||||
//
|
||||
// Note that the quantity will NEVER be internally represented by a
|
||||
// floating point number. That is the whole point of this exercise.
|
||||
//
|
||||
// Non-canonical values will still parse as long as they are well formed,
|
||||
// but will be re-emitted in their canonical form. (So always use canonical
|
||||
// form, or don't diff.)
|
||||
//
|
||||
// This format is intended to make it difficult to use these numbers without
|
||||
// writing some sort of special handling code in the hopes that that will
|
||||
// cause implementors to also use a fixed point implementation.
|
||||
//
|
||||
// +protobuf=true
|
||||
// +protobuf.embed=string
|
||||
// +protobuf.options.marshal=false
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
// +k8s:deepcopy-gen=true
|
||||
// +k8s:openapi-gen=true
|
||||
type Quantity struct {
|
||||
// i is the quantity in int64 scaled form, if d.Dec == nil
|
||||
i int64Amount
|
||||
// d is the quantity in inf.Dec form if d.Dec != nil
|
||||
d infDecAmount
|
||||
// s is the generated value of this quantity to avoid recalculation
|
||||
s string
|
||||
|
||||
// Change Format at will. See the comment for Canonicalize for
|
||||
// more details.
|
||||
Format
|
||||
}
|
||||
|
||||
// CanonicalValue allows a quantity amount to be converted to a string.
|
||||
type CanonicalValue interface {
|
||||
// AsCanonicalBytes returns a byte array representing the string representation
|
||||
// of the value mantissa and an int32 representing its exponent in base-10. Callers may
|
||||
// pass a byte slice to the method to avoid allocations.
|
||||
AsCanonicalBytes(out []byte) ([]byte, int32)
|
||||
// AsCanonicalBase1024Bytes returns a byte array representing the string representation
|
||||
// of the value mantissa and an int32 representing its exponent in base-1024. Callers
|
||||
// may pass a byte slice to the method to avoid allocations.
|
||||
AsCanonicalBase1024Bytes(out []byte) ([]byte, int32)
|
||||
}
|
||||
|
||||
// Format lists the three possible formattings of a quantity.
|
||||
type Format string
|
||||
|
||||
const (
|
||||
DecimalExponent = Format("DecimalExponent") // e.g., 12e6
|
||||
BinarySI = Format("BinarySI") // e.g., 12Mi (12 * 2^20)
|
||||
DecimalSI = Format("DecimalSI") // e.g., 12M (12 * 10^6)
|
||||
)
|
||||
|
||||
// MustParse turns the given string into a quantity or panics; for tests
|
||||
// or others cases where you know the string is valid.
|
||||
func MustParse(str string) Quantity {
|
||||
q, err := ParseQuantity(str)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot parse '%v': %v", str, err))
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
const (
|
||||
// splitREString is used to separate a number from its suffix; as such,
|
||||
// this is overly permissive, but that's OK-- it will be checked later.
|
||||
splitREString = "^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$"
|
||||
)
|
||||
|
||||
var (
|
||||
// splitRE is used to get the various parts of a number.
|
||||
splitRE = regexp.MustCompile(splitREString)
|
||||
|
||||
// Errors that could happen while parsing a string.
|
||||
ErrFormatWrong = errors.New("quantities must match the regular expression '" + splitREString + "'")
|
||||
ErrNumeric = errors.New("unable to parse numeric part of quantity")
|
||||
ErrSuffix = errors.New("unable to parse quantity's suffix")
|
||||
)
|
||||
|
||||
// parseQuantityString is a fast scanner for quantity values.
|
||||
func parseQuantityString(str string) (positive bool, value, num, denom, suffix string, err error) {
|
||||
positive = true
|
||||
pos := 0
|
||||
end := len(str)
|
||||
|
||||
// handle leading sign
|
||||
if pos < end {
|
||||
switch str[0] {
|
||||
case '-':
|
||||
positive = false
|
||||
pos++
|
||||
case '+':
|
||||
pos++
|
||||
}
|
||||
}
|
||||
|
||||
// strip leading zeros
|
||||
Zeroes:
|
||||
for i := pos; ; i++ {
|
||||
if i >= end {
|
||||
num = "0"
|
||||
value = num
|
||||
return
|
||||
}
|
||||
switch str[i] {
|
||||
case '0':
|
||||
pos++
|
||||
default:
|
||||
break Zeroes
|
||||
}
|
||||
}
|
||||
|
||||
// extract the numerator
|
||||
Num:
|
||||
for i := pos; ; i++ {
|
||||
if i >= end {
|
||||
num = str[pos:end]
|
||||
value = str[0:end]
|
||||
return
|
||||
}
|
||||
switch str[i] {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
default:
|
||||
num = str[pos:i]
|
||||
pos = i
|
||||
break Num
|
||||
}
|
||||
}
|
||||
|
||||
// if we stripped all numerator positions, always return 0
|
||||
if len(num) == 0 {
|
||||
num = "0"
|
||||
}
|
||||
|
||||
// handle a denominator
|
||||
if pos < end && str[pos] == '.' {
|
||||
pos++
|
||||
Denom:
|
||||
for i := pos; ; i++ {
|
||||
if i >= end {
|
||||
denom = str[pos:end]
|
||||
value = str[0:end]
|
||||
return
|
||||
}
|
||||
switch str[i] {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
default:
|
||||
denom = str[pos:i]
|
||||
pos = i
|
||||
break Denom
|
||||
}
|
||||
}
|
||||
// TODO: we currently allow 1.G, but we may not want to in the future.
|
||||
// if len(denom) == 0 {
|
||||
// err = ErrFormatWrong
|
||||
// return
|
||||
// }
|
||||
}
|
||||
value = str[0:pos]
|
||||
|
||||
// grab the elements of the suffix
|
||||
suffixStart := pos
|
||||
for i := pos; ; i++ {
|
||||
if i >= end {
|
||||
suffix = str[suffixStart:end]
|
||||
return
|
||||
}
|
||||
if !strings.ContainsAny(str[i:i+1], "eEinumkKMGTP") {
|
||||
pos = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if pos < end {
|
||||
switch str[pos] {
|
||||
case '-', '+':
|
||||
pos++
|
||||
}
|
||||
}
|
||||
Suffix:
|
||||
for i := pos; ; i++ {
|
||||
if i >= end {
|
||||
suffix = str[suffixStart:end]
|
||||
return
|
||||
}
|
||||
switch str[i] {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
default:
|
||||
break Suffix
|
||||
}
|
||||
}
|
||||
// we encountered a non decimal in the Suffix loop, but the last character
|
||||
// was not a valid exponent
|
||||
err = ErrFormatWrong
|
||||
return
|
||||
}
|
||||
|
||||
// ParseQuantity turns str into a Quantity, or returns an error.
|
||||
func ParseQuantity(str string) (Quantity, error) {
|
||||
if len(str) == 0 {
|
||||
return Quantity{}, ErrFormatWrong
|
||||
}
|
||||
if str == "0" {
|
||||
return Quantity{Format: DecimalSI, s: str}, nil
|
||||
}
|
||||
|
||||
positive, value, num, denom, suf, err := parseQuantityString(str)
|
||||
if err != nil {
|
||||
return Quantity{}, err
|
||||
}
|
||||
|
||||
base, exponent, format, ok := quantitySuffixer.interpret(suffix(suf))
|
||||
if !ok {
|
||||
return Quantity{}, ErrSuffix
|
||||
}
|
||||
|
||||
precision := int32(0)
|
||||
scale := int32(0)
|
||||
mantissa := int64(1)
|
||||
switch format {
|
||||
case DecimalExponent, DecimalSI:
|
||||
scale = exponent
|
||||
precision = maxInt64Factors - int32(len(num)+len(denom))
|
||||
case BinarySI:
|
||||
scale = 0
|
||||
switch {
|
||||
case exponent >= 0 && len(denom) == 0:
|
||||
// only handle positive binary numbers with the fast path
|
||||
mantissa = int64(int64(mantissa) << uint64(exponent))
|
||||
// 1Mi (2^20) has ~6 digits of decimal precision, so exponent*3/10 -1 is roughly the precision
|
||||
precision = 15 - int32(len(num)) - int32(float32(exponent)*3/10) - 1
|
||||
default:
|
||||
precision = -1
|
||||
}
|
||||
}
|
||||
|
||||
if precision >= 0 {
|
||||
// if we have a denominator, shift the entire value to the left by the number of places in the
|
||||
// denominator
|
||||
scale -= int32(len(denom))
|
||||
if scale >= int32(Nano) {
|
||||
shifted := num + denom
|
||||
|
||||
var value int64
|
||||
value, err := strconv.ParseInt(shifted, 10, 64)
|
||||
if err != nil {
|
||||
return Quantity{}, ErrNumeric
|
||||
}
|
||||
if result, ok := int64Multiply(value, int64(mantissa)); ok {
|
||||
if !positive {
|
||||
result = -result
|
||||
}
|
||||
// if the number is in canonical form, reuse the string
|
||||
switch format {
|
||||
case BinarySI:
|
||||
if exponent%10 == 0 && (value&0x07 != 0) {
|
||||
return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format, s: str}, nil
|
||||
}
|
||||
default:
|
||||
if scale%3 == 0 && !strings.HasSuffix(shifted, "000") && shifted[0] != '0' {
|
||||
return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format, s: str}, nil
|
||||
}
|
||||
}
|
||||
return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
amount := new(inf.Dec)
|
||||
if _, ok := amount.SetString(value); !ok {
|
||||
return Quantity{}, ErrNumeric
|
||||
}
|
||||
|
||||
// So that no one but us has to think about suffixes, remove it.
|
||||
if base == 10 {
|
||||
amount.SetScale(amount.Scale() + Scale(exponent).infScale())
|
||||
} else if base == 2 {
|
||||
// numericSuffix = 2 ** exponent
|
||||
numericSuffix := big.NewInt(1).Lsh(bigOne, uint(exponent))
|
||||
ub := amount.UnscaledBig()
|
||||
amount.SetUnscaledBig(ub.Mul(ub, numericSuffix))
|
||||
}
|
||||
|
||||
// Cap at min/max bounds.
|
||||
sign := amount.Sign()
|
||||
if sign == -1 {
|
||||
amount.Neg(amount)
|
||||
}
|
||||
|
||||
// This rounds non-zero values up to the minimum representable value, under the theory that
|
||||
// if you want some resources, you should get some resources, even if you asked for way too small
|
||||
// of an amount. Arguably, this should be inf.RoundHalfUp (normal rounding), but that would have
|
||||
// the side effect of rounding values < .5n to zero.
|
||||
if v, ok := amount.Unscaled(); v != int64(0) || !ok {
|
||||
amount.Round(amount, Nano.infScale(), inf.RoundUp)
|
||||
}
|
||||
|
||||
// The max is just a simple cap.
|
||||
// TODO: this prevents accumulating quantities greater than int64, for instance quota across a cluster
|
||||
if format == BinarySI && amount.Cmp(maxAllowed.Dec) > 0 {
|
||||
amount.Set(maxAllowed.Dec)
|
||||
}
|
||||
|
||||
if format == BinarySI && amount.Cmp(decOne) < 0 && amount.Cmp(decZero) > 0 {
|
||||
// This avoids rounding and hopefully confusion, too.
|
||||
format = DecimalSI
|
||||
}
|
||||
if sign == -1 {
|
||||
amount.Neg(amount)
|
||||
}
|
||||
|
||||
return Quantity{d: infDecAmount{amount}, Format: format}, nil
|
||||
}
|
||||
|
||||
// DeepCopy returns a deep-copy of the Quantity value. Note that the method
|
||||
// receiver is a value, so we can mutate it in-place and return it.
|
||||
func (q Quantity) DeepCopy() Quantity {
|
||||
if q.d.Dec != nil {
|
||||
tmp := &inf.Dec{}
|
||||
q.d.Dec = tmp.Set(q.d.Dec)
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
// OpenAPIDefinition returns openAPI definition for this type.
|
||||
func (_ Quantity) OpenAPIDefinition() openapi.OpenAPIDefinition {
|
||||
return openapi.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CanonicalizeBytes returns the canonical form of q and its suffix (see comment on Quantity).
|
||||
//
|
||||
// Note about BinarySI:
|
||||
// * If q.Format is set to BinarySI and q.Amount represents a non-zero value between
|
||||
// -1 and +1, it will be emitted as if q.Format were DecimalSI.
|
||||
// * Otherwise, if q.Format is set to BinarySI, fractional parts of q.Amount will be
|
||||
// rounded up. (1.1i becomes 2i.)
|
||||
func (q *Quantity) CanonicalizeBytes(out []byte) (result, suffix []byte) {
|
||||
if q.IsZero() {
|
||||
return zeroBytes, nil
|
||||
}
|
||||
|
||||
var rounded CanonicalValue
|
||||
format := q.Format
|
||||
switch format {
|
||||
case DecimalExponent, DecimalSI:
|
||||
case BinarySI:
|
||||
if q.CmpInt64(-1024) > 0 && q.CmpInt64(1024) < 0 {
|
||||
// This avoids rounding and hopefully confusion, too.
|
||||
format = DecimalSI
|
||||
} else {
|
||||
var exact bool
|
||||
if rounded, exact = q.AsScale(0); !exact {
|
||||
// Don't lose precision-- show as DecimalSI
|
||||
format = DecimalSI
|
||||
}
|
||||
}
|
||||
default:
|
||||
format = DecimalExponent
|
||||
}
|
||||
|
||||
// TODO: If BinarySI formatting is requested but would cause rounding, upgrade to
|
||||
// one of the other formats.
|
||||
switch format {
|
||||
case DecimalExponent, DecimalSI:
|
||||
number, exponent := q.AsCanonicalBytes(out)
|
||||
suffix, _ := quantitySuffixer.constructBytes(10, exponent, format)
|
||||
return number, suffix
|
||||
default:
|
||||
// format must be BinarySI
|
||||
number, exponent := rounded.AsCanonicalBase1024Bytes(out)
|
||||
suffix, _ := quantitySuffixer.constructBytes(2, exponent*10, format)
|
||||
return number, suffix
|
||||
}
|
||||
}
|
||||
|
||||
// AsInt64 returns a representation of the current value as an int64 if a fast conversion
|
||||
// is possible. If false is returned, callers must use the inf.Dec form of this quantity.
|
||||
func (q *Quantity) AsInt64() (int64, bool) {
|
||||
if q.d.Dec != nil {
|
||||
return 0, false
|
||||
}
|
||||
return q.i.AsInt64()
|
||||
}
|
||||
|
||||
// ToDec promotes the quantity in place to use an inf.Dec representation and returns itself.
|
||||
func (q *Quantity) ToDec() *Quantity {
|
||||
if q.d.Dec == nil {
|
||||
q.d.Dec = q.i.AsDec()
|
||||
q.i = int64Amount{}
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
// AsDec returns the quantity as represented by a scaled inf.Dec.
|
||||
func (q *Quantity) AsDec() *inf.Dec {
|
||||
if q.d.Dec != nil {
|
||||
return q.d.Dec
|
||||
}
|
||||
q.d.Dec = q.i.AsDec()
|
||||
q.i = int64Amount{}
|
||||
return q.d.Dec
|
||||
}
|
||||
|
||||
// AsCanonicalBytes returns the canonical byte representation of this quantity as a mantissa
|
||||
// and base 10 exponent. The out byte slice may be passed to the method to avoid an extra
|
||||
// allocation.
|
||||
func (q *Quantity) AsCanonicalBytes(out []byte) (result []byte, exponent int32) {
|
||||
if q.d.Dec != nil {
|
||||
return q.d.AsCanonicalBytes(out)
|
||||
}
|
||||
return q.i.AsCanonicalBytes(out)
|
||||
}
|
||||
|
||||
// IsZero returns true if the quantity is equal to zero.
|
||||
func (q *Quantity) IsZero() bool {
|
||||
if q.d.Dec != nil {
|
||||
return q.d.Dec.Sign() == 0
|
||||
}
|
||||
return q.i.value == 0
|
||||
}
|
||||
|
||||
// Sign returns 0 if the quantity is zero, -1 if the quantity is less than zero, or 1 if the
|
||||
// quantity is greater than zero.
|
||||
func (q *Quantity) Sign() int {
|
||||
if q.d.Dec != nil {
|
||||
return q.d.Dec.Sign()
|
||||
}
|
||||
return q.i.Sign()
|
||||
}
|
||||
|
||||
// AsScaled returns the current value, rounded up to the provided scale, and returns
|
||||
// false if the scale resulted in a loss of precision.
|
||||
func (q *Quantity) AsScale(scale Scale) (CanonicalValue, bool) {
|
||||
if q.d.Dec != nil {
|
||||
return q.d.AsScale(scale)
|
||||
}
|
||||
return q.i.AsScale(scale)
|
||||
}
|
||||
|
||||
// RoundUp updates the quantity to the provided scale, ensuring that the value is at
|
||||
// least 1. False is returned if the rounding operation resulted in a loss of precision.
|
||||
// Negative numbers are rounded away from zero (-9 scale 1 rounds to -10).
|
||||
func (q *Quantity) RoundUp(scale Scale) bool {
|
||||
if q.d.Dec != nil {
|
||||
q.s = ""
|
||||
d, exact := q.d.AsScale(scale)
|
||||
q.d = d
|
||||
return exact
|
||||
}
|
||||
// avoid clearing the string value if we have already calculated it
|
||||
if q.i.scale >= scale {
|
||||
return true
|
||||
}
|
||||
q.s = ""
|
||||
i, exact := q.i.AsScale(scale)
|
||||
q.i = i
|
||||
return exact
|
||||
}
|
||||
|
||||
// Add adds the provide y quantity to the current value. If the current value is zero,
|
||||
// the format of the quantity will be updated to the format of y.
|
||||
func (q *Quantity) Add(y Quantity) {
|
||||
q.s = ""
|
||||
if q.d.Dec == nil && y.d.Dec == nil {
|
||||
if q.i.value == 0 {
|
||||
q.Format = y.Format
|
||||
}
|
||||
if q.i.Add(y.i) {
|
||||
return
|
||||
}
|
||||
} else if q.IsZero() {
|
||||
q.Format = y.Format
|
||||
}
|
||||
q.ToDec().d.Dec.Add(q.d.Dec, y.AsDec())
|
||||
}
|
||||
|
||||
// Sub subtracts the provided quantity from the current value in place. If the current
|
||||
// value is zero, the format of the quantity will be updated to the format of y.
|
||||
func (q *Quantity) Sub(y Quantity) {
|
||||
q.s = ""
|
||||
if q.IsZero() {
|
||||
q.Format = y.Format
|
||||
}
|
||||
if q.d.Dec == nil && y.d.Dec == nil && q.i.Sub(y.i) {
|
||||
return
|
||||
}
|
||||
q.ToDec().d.Dec.Sub(q.d.Dec, y.AsDec())
|
||||
}
|
||||
|
||||
// Cmp returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the
|
||||
// quantity is greater than y.
|
||||
func (q *Quantity) Cmp(y Quantity) int {
|
||||
if q.d.Dec == nil && y.d.Dec == nil {
|
||||
return q.i.Cmp(y.i)
|
||||
}
|
||||
return q.AsDec().Cmp(y.AsDec())
|
||||
}
|
||||
|
||||
// CmpInt64 returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the
|
||||
// quantity is greater than y.
|
||||
func (q *Quantity) CmpInt64(y int64) int {
|
||||
if q.d.Dec != nil {
|
||||
return q.d.Dec.Cmp(inf.NewDec(y, inf.Scale(0)))
|
||||
}
|
||||
return q.i.Cmp(int64Amount{value: y})
|
||||
}
|
||||
|
||||
// Neg sets quantity to be the negative value of itself.
|
||||
func (q *Quantity) Neg() {
|
||||
q.s = ""
|
||||
if q.d.Dec == nil {
|
||||
q.i.value = -q.i.value
|
||||
return
|
||||
}
|
||||
q.d.Dec.Neg(q.d.Dec)
|
||||
}
|
||||
|
||||
// int64QuantityExpectedBytes is the expected width in bytes of the canonical string representation
|
||||
// of most Quantity values.
|
||||
const int64QuantityExpectedBytes = 18
|
||||
|
||||
// String formats the Quantity as a string, caching the result if not calculated.
|
||||
// String is an expensive operation and caching this result significantly reduces the cost of
|
||||
// normal parse / marshal operations on Quantity.
|
||||
func (q *Quantity) String() string {
|
||||
if len(q.s) == 0 {
|
||||
result := make([]byte, 0, int64QuantityExpectedBytes)
|
||||
number, suffix := q.CanonicalizeBytes(result)
|
||||
number = append(number, suffix...)
|
||||
q.s = string(number)
|
||||
}
|
||||
return q.s
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaller interface.
|
||||
func (q Quantity) MarshalJSON() ([]byte, error) {
|
||||
if len(q.s) > 0 {
|
||||
out := make([]byte, len(q.s)+2)
|
||||
out[0], out[len(out)-1] = '"', '"'
|
||||
copy(out[1:], q.s)
|
||||
return out, nil
|
||||
}
|
||||
result := make([]byte, int64QuantityExpectedBytes, int64QuantityExpectedBytes)
|
||||
result[0] = '"'
|
||||
number, suffix := q.CanonicalizeBytes(result[1:1])
|
||||
// if the same slice was returned to us that we passed in, avoid another allocation by copying number into
|
||||
// the source slice and returning that
|
||||
if len(number) > 0 && &number[0] == &result[1] && (len(number)+len(suffix)+2) <= int64QuantityExpectedBytes {
|
||||
number = append(number, suffix...)
|
||||
number = append(number, '"')
|
||||
return result[:1+len(number)], nil
|
||||
}
|
||||
// if CanonicalizeBytes needed more space than our slice provided, we may need to allocate again so use
|
||||
// append
|
||||
result = result[:1]
|
||||
result = append(result, number...)
|
||||
result = append(result, suffix...)
|
||||
result = append(result, '"')
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaller interface.
|
||||
// TODO: Remove support for leading/trailing whitespace
|
||||
func (q *Quantity) UnmarshalJSON(value []byte) error {
|
||||
l := len(value)
|
||||
if l == 4 && bytes.Equal(value, []byte("null")) {
|
||||
q.d.Dec = nil
|
||||
q.i = int64Amount{}
|
||||
return nil
|
||||
}
|
||||
if l >= 2 && value[0] == '"' && value[l-1] == '"' {
|
||||
value = value[1 : l-1]
|
||||
}
|
||||
|
||||
parsed, err := ParseQuantity(strings.TrimSpace(string(value)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// This copy is safe because parsed will not be referred to again.
|
||||
*q = parsed
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewQuantity returns a new Quantity representing the given
|
||||
// value in the given format.
|
||||
func NewQuantity(value int64, format Format) *Quantity {
|
||||
return &Quantity{
|
||||
i: int64Amount{value: value},
|
||||
Format: format,
|
||||
}
|
||||
}
|
||||
|
||||
// NewMilliQuantity returns a new Quantity representing the given
|
||||
// value * 1/1000 in the given format. Note that BinarySI formatting
|
||||
// will round fractional values, and will be changed to DecimalSI for
|
||||
// values x where (-1 < x < 1) && (x != 0).
|
||||
func NewMilliQuantity(value int64, format Format) *Quantity {
|
||||
return &Quantity{
|
||||
i: int64Amount{value: value, scale: -3},
|
||||
Format: format,
|
||||
}
|
||||
}
|
||||
|
||||
// NewScaledQuantity returns a new Quantity representing the given
|
||||
// value * 10^scale in DecimalSI format.
|
||||
func NewScaledQuantity(value int64, scale Scale) *Quantity {
|
||||
return &Quantity{
|
||||
i: int64Amount{value: value, scale: scale},
|
||||
Format: DecimalSI,
|
||||
}
|
||||
}
|
||||
|
||||
// Value returns the value of q; any fractional part will be lost.
|
||||
func (q *Quantity) Value() int64 {
|
||||
return q.ScaledValue(0)
|
||||
}
|
||||
|
||||
// MilliValue returns the value of ceil(q * 1000); this could overflow an int64;
|
||||
// if that's a concern, call Value() first to verify the number is small enough.
|
||||
func (q *Quantity) MilliValue() int64 {
|
||||
return q.ScaledValue(Milli)
|
||||
}
|
||||
|
||||
// ScaledValue returns the value of ceil(q * 10^scale); this could overflow an int64.
|
||||
// To detect overflow, call Value() first and verify the expected magnitude.
|
||||
func (q *Quantity) ScaledValue(scale Scale) int64 {
|
||||
if q.d.Dec == nil {
|
||||
i, _ := q.i.AsScaledInt64(scale)
|
||||
return i
|
||||
}
|
||||
dec := q.d.Dec
|
||||
return scaledValue(dec.UnscaledBig(), int(dec.Scale()), int(scale.infScale()))
|
||||
}
|
||||
|
||||
// Set sets q's value to be value.
|
||||
func (q *Quantity) Set(value int64) {
|
||||
q.SetScaled(value, 0)
|
||||
}
|
||||
|
||||
// SetMilli sets q's value to be value * 1/1000.
|
||||
func (q *Quantity) SetMilli(value int64) {
|
||||
q.SetScaled(value, Milli)
|
||||
}
|
||||
|
||||
// SetScaled sets q's value to be value * 10^scale
|
||||
func (q *Quantity) SetScaled(value int64, scale Scale) {
|
||||
q.s = ""
|
||||
q.d.Dec = nil
|
||||
q.i = int64Amount{value: value, scale: scale}
|
||||
}
|
||||
|
||||
// Copy is a convenience function that makes a deep copy for you. Non-deep
|
||||
// copies of quantities share pointers and you will regret that.
|
||||
func (q *Quantity) Copy() *Quantity {
|
||||
if q.d.Dec == nil {
|
||||
return &Quantity{
|
||||
s: q.s,
|
||||
i: q.i,
|
||||
Format: q.Format,
|
||||
}
|
||||
}
|
||||
tmp := &inf.Dec{}
|
||||
return &Quantity{
|
||||
s: q.s,
|
||||
d: infDecAmount{tmp.Set(q.d.Dec)},
|
||||
Format: q.Format,
|
||||
}
|
||||
}
|
||||
|
||||
// qFlag is a helper type for the Flag function
|
||||
type qFlag struct {
|
||||
dest *Quantity
|
||||
}
|
||||
|
||||
// Sets the value of the internal Quantity. (used by flag & pflag)
|
||||
func (qf qFlag) Set(val string) error {
|
||||
q, err := ParseQuantity(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// This copy is OK because q will not be referenced again.
|
||||
*qf.dest = q
|
||||
return nil
|
||||
}
|
||||
|
||||
// Converts the value of the internal Quantity to a string. (used by flag & pflag)
|
||||
func (qf qFlag) String() string {
|
||||
return qf.dest.String()
|
||||
}
|
||||
|
||||
// States the type of flag this is (Quantity). (used by pflag)
|
||||
func (qf qFlag) Type() string {
|
||||
return "quantity"
|
||||
}
|
||||
|
||||
// QuantityFlag is a helper that makes a quantity flag (using standard flag package).
|
||||
// Will panic if defaultValue is not a valid quantity.
|
||||
func QuantityFlag(flagName, defaultValue, description string) *Quantity {
|
||||
q := MustParse(defaultValue)
|
||||
flag.Var(NewQuantityFlagValue(&q), flagName, description)
|
||||
return &q
|
||||
}
|
||||
|
||||
// NewQuantityFlagValue returns an object that can be used to back a flag,
|
||||
// pointing at the given Quantity variable.
|
||||
func NewQuantityFlagValue(q *Quantity) flag.Value {
|
||||
return qFlag{q}
|
||||
}
|
59
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_example_test.go
generated
vendored
Normal file
59
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_example_test.go
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
Copyright 2014 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 resource_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
)
|
||||
|
||||
func ExampleFormat() {
|
||||
memorySize := resource.NewQuantity(5*1024*1024*1024, resource.BinarySI)
|
||||
fmt.Printf("memorySize = %v\n", memorySize)
|
||||
|
||||
diskSize := resource.NewQuantity(5*1000*1000*1000, resource.DecimalSI)
|
||||
fmt.Printf("diskSize = %v\n", diskSize)
|
||||
|
||||
cores := resource.NewMilliQuantity(5300, resource.DecimalSI)
|
||||
fmt.Printf("cores = %v\n", cores)
|
||||
|
||||
// Output:
|
||||
// memorySize = 5Gi
|
||||
// diskSize = 5G
|
||||
// cores = 5300m
|
||||
}
|
||||
|
||||
func ExampleMustParse() {
|
||||
memorySize := resource.MustParse("5Gi")
|
||||
fmt.Printf("memorySize = %v (%v)\n", memorySize.Value(), memorySize.Format)
|
||||
|
||||
diskSize := resource.MustParse("5G")
|
||||
fmt.Printf("diskSize = %v (%v)\n", diskSize.Value(), diskSize.Format)
|
||||
|
||||
cores := resource.MustParse("5300m")
|
||||
fmt.Printf("milliCores = %v (%v)\n", cores.MilliValue(), cores.Format)
|
||||
|
||||
cores2 := resource.MustParse("5.4")
|
||||
fmt.Printf("milliCores = %v (%v)\n", cores2.MilliValue(), cores2.Format)
|
||||
|
||||
// Output:
|
||||
// memorySize = 5368709120 (BinarySI)
|
||||
// diskSize = 5000000000 (DecimalSI)
|
||||
// milliCores = 5300 (DecimalSI)
|
||||
// milliCores = 5400 (DecimalSI)
|
||||
}
|
284
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_proto.go
generated
vendored
Normal file
284
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_proto.go
generated
vendored
Normal file
@ -0,0 +1,284 @@
|
||||
/*
|
||||
Copyright 2015 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 resource
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
var _ proto.Sizer = &Quantity{}
|
||||
|
||||
func (m *Quantity) Marshal() (data []byte, err error) {
|
||||
size := m.Size()
|
||||
data = make([]byte, size)
|
||||
n, err := m.MarshalTo(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data[:n], nil
|
||||
}
|
||||
|
||||
// MarshalTo is a customized version of the generated Protobuf unmarshaler for a struct
|
||||
// with a single string field.
|
||||
func (m *Quantity) MarshalTo(data []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
|
||||
data[i] = 0xa
|
||||
i++
|
||||
// BEGIN CUSTOM MARSHAL
|
||||
out := m.String()
|
||||
i = encodeVarintGenerated(data, i, uint64(len(out)))
|
||||
i += copy(data[i:], out)
|
||||
// END CUSTOM MARSHAL
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func encodeVarintGenerated(data []byte, offset int, v uint64) int {
|
||||
for v >= 1<<7 {
|
||||
data[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
data[offset] = uint8(v)
|
||||
return offset + 1
|
||||
}
|
||||
|
||||
func (m *Quantity) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
|
||||
// BEGIN CUSTOM SIZE
|
||||
l = len(m.String())
|
||||
// END CUSTOM SIZE
|
||||
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
return n
|
||||
}
|
||||
|
||||
func sovGenerated(x uint64) (n int) {
|
||||
for {
|
||||
n++
|
||||
x >>= 7
|
||||
if x == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Unmarshal is a customized version of the generated Protobuf unmarshaler for a struct
|
||||
// with a single string field.
|
||||
func (m *Quantity) Unmarshal(data []byte) error {
|
||||
l := len(data)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: Quantity: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: Quantity: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field String_", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
s := string(data[iNdEx:postIndex])
|
||||
|
||||
// BEGIN CUSTOM DECODE
|
||||
p, err := ParseQuantity(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*m = p
|
||||
// END CUSTOM DECODE
|
||||
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(data[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func skipGenerated(data []byte) (n int, err error) {
|
||||
l := len(data)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if data[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
return iNdEx, nil
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
iNdEx += length
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthGenerated
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 3:
|
||||
for {
|
||||
var innerWire uint64
|
||||
var start int = iNdEx
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
innerWire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
innerWireType := int(innerWire & 0x7)
|
||||
if innerWireType == 4 {
|
||||
break
|
||||
}
|
||||
next, err := skipGenerated(data[start:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
iNdEx = start + next
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 4:
|
||||
return iNdEx, nil
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
return iNdEx, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow")
|
||||
)
|
103
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_proto_test.go
generated
vendored
Normal file
103
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_proto_test.go
generated
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
Copyright 2017 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 resource
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
inf "gopkg.in/inf.v0"
|
||||
)
|
||||
|
||||
func TestQuantityProtoMarshal(t *testing.T) {
|
||||
// Test when d is nil
|
||||
table := []struct {
|
||||
quantity string
|
||||
expect Quantity
|
||||
}{
|
||||
{"0", Quantity{i: int64Amount{value: 0, scale: 0}, s: "0", Format: DecimalSI}},
|
||||
{"100m", Quantity{i: int64Amount{value: 100, scale: -3}, s: "100m", Format: DecimalSI}},
|
||||
{"50m", Quantity{i: int64Amount{value: 50, scale: -3}, s: "50m", Format: DecimalSI}},
|
||||
{"10000T", Quantity{i: int64Amount{value: 10000, scale: 12}, s: "10000T", Format: DecimalSI}},
|
||||
}
|
||||
for _, testCase := range table {
|
||||
q := MustParse(testCase.quantity)
|
||||
// Won't currently get an error as MarshalTo can't return one
|
||||
result, _ := q.Marshal()
|
||||
q.MarshalTo(result)
|
||||
if q.Cmp(testCase.expect) != 0 {
|
||||
t.Errorf("Expected: %v, Actual: %v", testCase.expect, q)
|
||||
}
|
||||
}
|
||||
// Test when i is {0,0}
|
||||
table2 := []struct {
|
||||
dec *inf.Dec
|
||||
expect Quantity
|
||||
}{
|
||||
{dec(0, 0).Dec, Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(0, 0).Dec}, s: "0", Format: DecimalSI}},
|
||||
{dec(10, 0).Dec, Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(10, 0).Dec}, s: "10", Format: DecimalSI}},
|
||||
{dec(-10, 0).Dec, Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(-10, 0).Dec}, s: "-10", Format: DecimalSI}},
|
||||
}
|
||||
for _, testCase := range table2 {
|
||||
q := Quantity{d: infDecAmount{testCase.dec}, Format: DecimalSI}
|
||||
// Won't currently get an error as MarshalTo can't return one
|
||||
result, _ := q.Marshal()
|
||||
q.Unmarshal(result)
|
||||
if q.Cmp(testCase.expect) != 0 {
|
||||
t.Errorf("Expected: %v, Actual: %v", testCase.expect, q)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuantityProtoUnmarshal(t *testing.T) {
|
||||
// Test when d is nil
|
||||
table := []struct {
|
||||
input Quantity
|
||||
expect string
|
||||
}{
|
||||
{Quantity{i: int64Amount{value: 0, scale: 0}, s: "0", Format: DecimalSI}, "0"},
|
||||
{Quantity{i: int64Amount{value: 100, scale: -3}, s: "100m", Format: DecimalSI}, "100m"},
|
||||
{Quantity{i: int64Amount{value: 50, scale: -3}, s: "50m", Format: DecimalSI}, "50m"},
|
||||
{Quantity{i: int64Amount{value: 10000, scale: 12}, s: "10000T", Format: DecimalSI}, "10000T"},
|
||||
}
|
||||
for _, testCase := range table {
|
||||
var inputQ Quantity
|
||||
expectQ := MustParse(testCase.expect)
|
||||
inputByteArray, _ := testCase.input.Marshal()
|
||||
inputQ.Unmarshal(inputByteArray)
|
||||
if inputQ.Cmp(expectQ) != 0 {
|
||||
t.Errorf("Expected: %v, Actual: %v", inputQ, expectQ)
|
||||
}
|
||||
}
|
||||
// Test when i is {0,0}
|
||||
table2 := []struct {
|
||||
input Quantity
|
||||
expect *inf.Dec
|
||||
}{
|
||||
{Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(0, 0).Dec}, s: "0", Format: DecimalSI}, dec(0, 0).Dec},
|
||||
{Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(10, 0).Dec}, s: "10", Format: DecimalSI}, dec(10, 0).Dec},
|
||||
{Quantity{i: int64Amount{value: 0, scale: 0}, d: infDecAmount{dec(-10, 0).Dec}, s: "-10", Format: DecimalSI}, dec(-10, 0).Dec},
|
||||
}
|
||||
for _, testCase := range table2 {
|
||||
var inputQ Quantity
|
||||
expectQ := Quantity{d: infDecAmount{testCase.expect}, Format: DecimalSI}
|
||||
inputByteArray, _ := testCase.input.Marshal()
|
||||
inputQ.Unmarshal(inputByteArray)
|
||||
if inputQ.Cmp(expectQ) != 0 {
|
||||
t.Errorf("Expected: %v, Actual: %v", inputQ, expectQ)
|
||||
}
|
||||
}
|
||||
}
|
1368
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_test.go
generated
vendored
Normal file
1368
vendor/k8s.io/apimachinery/pkg/api/resource/quantity_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
95
vendor/k8s.io/apimachinery/pkg/api/resource/scale_int.go
generated
vendored
Normal file
95
vendor/k8s.io/apimachinery/pkg/api/resource/scale_int.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright 2015 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 resource
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
// A sync pool to reduce allocation.
|
||||
intPool sync.Pool
|
||||
maxInt64 = big.NewInt(math.MaxInt64)
|
||||
)
|
||||
|
||||
func init() {
|
||||
intPool.New = func() interface{} {
|
||||
return &big.Int{}
|
||||
}
|
||||
}
|
||||
|
||||
// scaledValue scales given unscaled value from scale to new Scale and returns
|
||||
// an int64. It ALWAYS rounds up the result when scale down. The final result might
|
||||
// overflow.
|
||||
//
|
||||
// scale, newScale represents the scale of the unscaled decimal.
|
||||
// The mathematical value of the decimal is unscaled * 10**(-scale).
|
||||
func scaledValue(unscaled *big.Int, scale, newScale int) int64 {
|
||||
dif := scale - newScale
|
||||
if dif == 0 {
|
||||
return unscaled.Int64()
|
||||
}
|
||||
|
||||
// Handle scale up
|
||||
// This is an easy case, we do not need to care about rounding and overflow.
|
||||
// If any intermediate operation causes overflow, the result will overflow.
|
||||
if dif < 0 {
|
||||
return unscaled.Int64() * int64(math.Pow10(-dif))
|
||||
}
|
||||
|
||||
// Handle scale down
|
||||
// We have to be careful about the intermediate operations.
|
||||
|
||||
// fast path when unscaled < max.Int64 and exp(10,dif) < max.Int64
|
||||
const log10MaxInt64 = 19
|
||||
if unscaled.Cmp(maxInt64) < 0 && dif < log10MaxInt64 {
|
||||
divide := int64(math.Pow10(dif))
|
||||
result := unscaled.Int64() / divide
|
||||
mod := unscaled.Int64() % divide
|
||||
if mod != 0 {
|
||||
return result + 1
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// We should only convert back to int64 when getting the result.
|
||||
divisor := intPool.Get().(*big.Int)
|
||||
exp := intPool.Get().(*big.Int)
|
||||
result := intPool.Get().(*big.Int)
|
||||
defer func() {
|
||||
intPool.Put(divisor)
|
||||
intPool.Put(exp)
|
||||
intPool.Put(result)
|
||||
}()
|
||||
|
||||
// divisor = 10^(dif)
|
||||
// TODO: create loop up table if exp costs too much.
|
||||
divisor.Exp(bigTen, exp.SetInt64(int64(dif)), nil)
|
||||
// reuse exp
|
||||
remainder := exp
|
||||
|
||||
// result = unscaled / divisor
|
||||
// remainder = unscaled % divisor
|
||||
result.DivMod(unscaled, divisor, remainder)
|
||||
if remainder.Sign() != 0 {
|
||||
return result.Int64() + 1
|
||||
}
|
||||
|
||||
return result.Int64()
|
||||
}
|
85
vendor/k8s.io/apimachinery/pkg/api/resource/scale_int_test.go
generated
vendored
Normal file
85
vendor/k8s.io/apimachinery/pkg/api/resource/scale_int_test.go
generated
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright 2015 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 resource
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestScaledValueInternal(t *testing.T) {
|
||||
tests := []struct {
|
||||
unscaled *big.Int
|
||||
scale int
|
||||
newScale int
|
||||
|
||||
want int64
|
||||
}{
|
||||
// remain scale
|
||||
{big.NewInt(1000), 0, 0, 1000},
|
||||
|
||||
// scale down
|
||||
{big.NewInt(1000), 0, -3, 1},
|
||||
{big.NewInt(1000), 3, 0, 1},
|
||||
{big.NewInt(0), 3, 0, 0},
|
||||
|
||||
// always round up
|
||||
{big.NewInt(999), 3, 0, 1},
|
||||
{big.NewInt(500), 3, 0, 1},
|
||||
{big.NewInt(499), 3, 0, 1},
|
||||
{big.NewInt(1), 3, 0, 1},
|
||||
// large scaled value does not lose precision
|
||||
{big.NewInt(0).Sub(maxInt64, bigOne), 1, 0, (math.MaxInt64-1)/10 + 1},
|
||||
// large intermidiate result.
|
||||
{big.NewInt(1).Exp(big.NewInt(10), big.NewInt(100), nil), 100, 0, 1},
|
||||
|
||||
// scale up
|
||||
{big.NewInt(0), 0, 3, 0},
|
||||
{big.NewInt(1), 0, 3, 1000},
|
||||
{big.NewInt(1), -3, 0, 1000},
|
||||
{big.NewInt(1000), -3, 2, 100000000},
|
||||
{big.NewInt(0).Div(big.NewInt(math.MaxInt64), bigThousand), 0, 3,
|
||||
(math.MaxInt64 / 1000) * 1000},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
old := (&big.Int{}).Set(tt.unscaled)
|
||||
got := scaledValue(tt.unscaled, tt.scale, tt.newScale)
|
||||
if got != tt.want {
|
||||
t.Errorf("#%d: got = %v, want %v", i, got, tt.want)
|
||||
}
|
||||
if tt.unscaled.Cmp(old) != 0 {
|
||||
t.Errorf("#%d: unscaled = %v, want %v", i, tt.unscaled, old)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkScaledValueSmall(b *testing.B) {
|
||||
s := big.NewInt(1000)
|
||||
for i := 0; i < b.N; i++ {
|
||||
scaledValue(s, 3, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkScaledValueLarge(b *testing.B) {
|
||||
s := big.NewInt(math.MaxInt64)
|
||||
s.Mul(s, big.NewInt(1000))
|
||||
for i := 0; i < b.N; i++ {
|
||||
scaledValue(s, 10, 0)
|
||||
}
|
||||
}
|
198
vendor/k8s.io/apimachinery/pkg/api/resource/suffix.go
generated
vendored
Normal file
198
vendor/k8s.io/apimachinery/pkg/api/resource/suffix.go
generated
vendored
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
Copyright 2014 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 resource
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type suffix string
|
||||
|
||||
// suffixer can interpret and construct suffixes.
|
||||
type suffixer interface {
|
||||
interpret(suffix) (base, exponent int32, fmt Format, ok bool)
|
||||
construct(base, exponent int32, fmt Format) (s suffix, ok bool)
|
||||
constructBytes(base, exponent int32, fmt Format) (s []byte, ok bool)
|
||||
}
|
||||
|
||||
// quantitySuffixer handles suffixes for all three formats that quantity
|
||||
// can handle.
|
||||
var quantitySuffixer = newSuffixer()
|
||||
|
||||
type bePair struct {
|
||||
base, exponent int32
|
||||
}
|
||||
|
||||
type listSuffixer struct {
|
||||
suffixToBE map[suffix]bePair
|
||||
beToSuffix map[bePair]suffix
|
||||
beToSuffixBytes map[bePair][]byte
|
||||
}
|
||||
|
||||
func (ls *listSuffixer) addSuffix(s suffix, pair bePair) {
|
||||
if ls.suffixToBE == nil {
|
||||
ls.suffixToBE = map[suffix]bePair{}
|
||||
}
|
||||
if ls.beToSuffix == nil {
|
||||
ls.beToSuffix = map[bePair]suffix{}
|
||||
}
|
||||
if ls.beToSuffixBytes == nil {
|
||||
ls.beToSuffixBytes = map[bePair][]byte{}
|
||||
}
|
||||
ls.suffixToBE[s] = pair
|
||||
ls.beToSuffix[pair] = s
|
||||
ls.beToSuffixBytes[pair] = []byte(s)
|
||||
}
|
||||
|
||||
func (ls *listSuffixer) lookup(s suffix) (base, exponent int32, ok bool) {
|
||||
pair, ok := ls.suffixToBE[s]
|
||||
if !ok {
|
||||
return 0, 0, false
|
||||
}
|
||||
return pair.base, pair.exponent, true
|
||||
}
|
||||
|
||||
func (ls *listSuffixer) construct(base, exponent int32) (s suffix, ok bool) {
|
||||
s, ok = ls.beToSuffix[bePair{base, exponent}]
|
||||
return
|
||||
}
|
||||
|
||||
func (ls *listSuffixer) constructBytes(base, exponent int32) (s []byte, ok bool) {
|
||||
s, ok = ls.beToSuffixBytes[bePair{base, exponent}]
|
||||
return
|
||||
}
|
||||
|
||||
type suffixHandler struct {
|
||||
decSuffixes listSuffixer
|
||||
binSuffixes listSuffixer
|
||||
}
|
||||
|
||||
type fastLookup struct {
|
||||
*suffixHandler
|
||||
}
|
||||
|
||||
func (l fastLookup) interpret(s suffix) (base, exponent int32, format Format, ok bool) {
|
||||
switch s {
|
||||
case "":
|
||||
return 10, 0, DecimalSI, true
|
||||
case "n":
|
||||
return 10, -9, DecimalSI, true
|
||||
case "u":
|
||||
return 10, -6, DecimalSI, true
|
||||
case "m":
|
||||
return 10, -3, DecimalSI, true
|
||||
case "k":
|
||||
return 10, 3, DecimalSI, true
|
||||
case "M":
|
||||
return 10, 6, DecimalSI, true
|
||||
case "G":
|
||||
return 10, 9, DecimalSI, true
|
||||
}
|
||||
return l.suffixHandler.interpret(s)
|
||||
}
|
||||
|
||||
func newSuffixer() suffixer {
|
||||
sh := &suffixHandler{}
|
||||
|
||||
// IMPORTANT: if you change this section you must change fastLookup
|
||||
|
||||
sh.binSuffixes.addSuffix("Ki", bePair{2, 10})
|
||||
sh.binSuffixes.addSuffix("Mi", bePair{2, 20})
|
||||
sh.binSuffixes.addSuffix("Gi", bePair{2, 30})
|
||||
sh.binSuffixes.addSuffix("Ti", bePair{2, 40})
|
||||
sh.binSuffixes.addSuffix("Pi", bePair{2, 50})
|
||||
sh.binSuffixes.addSuffix("Ei", bePair{2, 60})
|
||||
// Don't emit an error when trying to produce
|
||||
// a suffix for 2^0.
|
||||
sh.decSuffixes.addSuffix("", bePair{2, 0})
|
||||
|
||||
sh.decSuffixes.addSuffix("n", bePair{10, -9})
|
||||
sh.decSuffixes.addSuffix("u", bePair{10, -6})
|
||||
sh.decSuffixes.addSuffix("m", bePair{10, -3})
|
||||
sh.decSuffixes.addSuffix("", bePair{10, 0})
|
||||
sh.decSuffixes.addSuffix("k", bePair{10, 3})
|
||||
sh.decSuffixes.addSuffix("M", bePair{10, 6})
|
||||
sh.decSuffixes.addSuffix("G", bePair{10, 9})
|
||||
sh.decSuffixes.addSuffix("T", bePair{10, 12})
|
||||
sh.decSuffixes.addSuffix("P", bePair{10, 15})
|
||||
sh.decSuffixes.addSuffix("E", bePair{10, 18})
|
||||
|
||||
return fastLookup{sh}
|
||||
}
|
||||
|
||||
func (sh *suffixHandler) construct(base, exponent int32, fmt Format) (s suffix, ok bool) {
|
||||
switch fmt {
|
||||
case DecimalSI:
|
||||
return sh.decSuffixes.construct(base, exponent)
|
||||
case BinarySI:
|
||||
return sh.binSuffixes.construct(base, exponent)
|
||||
case DecimalExponent:
|
||||
if base != 10 {
|
||||
return "", false
|
||||
}
|
||||
if exponent == 0 {
|
||||
return "", true
|
||||
}
|
||||
return suffix("e" + strconv.FormatInt(int64(exponent), 10)), true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (sh *suffixHandler) constructBytes(base, exponent int32, format Format) (s []byte, ok bool) {
|
||||
switch format {
|
||||
case DecimalSI:
|
||||
return sh.decSuffixes.constructBytes(base, exponent)
|
||||
case BinarySI:
|
||||
return sh.binSuffixes.constructBytes(base, exponent)
|
||||
case DecimalExponent:
|
||||
if base != 10 {
|
||||
return nil, false
|
||||
}
|
||||
if exponent == 0 {
|
||||
return nil, true
|
||||
}
|
||||
result := make([]byte, 8, 8)
|
||||
result[0] = 'e'
|
||||
number := strconv.AppendInt(result[1:1], int64(exponent), 10)
|
||||
if &result[1] == &number[0] {
|
||||
return result[:1+len(number)], true
|
||||
}
|
||||
result = append(result[:1], number...)
|
||||
return result, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (sh *suffixHandler) interpret(suffix suffix) (base, exponent int32, fmt Format, ok bool) {
|
||||
// Try lookup tables first
|
||||
if b, e, ok := sh.decSuffixes.lookup(suffix); ok {
|
||||
return b, e, DecimalSI, true
|
||||
}
|
||||
if b, e, ok := sh.binSuffixes.lookup(suffix); ok {
|
||||
return b, e, BinarySI, true
|
||||
}
|
||||
|
||||
if len(suffix) > 1 && (suffix[0] == 'E' || suffix[0] == 'e') {
|
||||
parsed, err := strconv.ParseInt(string(suffix[1:]), 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, DecimalExponent, false
|
||||
}
|
||||
return 10, int32(parsed), DecimalExponent, true
|
||||
}
|
||||
|
||||
return 0, 0, DecimalExponent, false
|
||||
}
|
27
vendor/k8s.io/apimachinery/pkg/api/resource/zz_generated.deepcopy.go
generated
vendored
Normal file
27
vendor/k8s.io/apimachinery/pkg/api/resource/zz_generated.deepcopy.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2017 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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package resource
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Quantity) DeepCopyInto(out *Quantity) {
|
||||
*out = in.DeepCopy()
|
||||
return
|
||||
}
|
35
vendor/k8s.io/apimachinery/pkg/api/testing/BUILD
generated
vendored
Normal file
35
vendor/k8s.io/apimachinery/pkg/api/testing/BUILD
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["codec.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/testing",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/recognizer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/testing/fuzzer:all-srcs",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/testing/roundtrip:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
86
vendor/k8s.io/apimachinery/pkg/api/testing/codec.go
generated
vendored
Normal file
86
vendor/k8s.io/apimachinery/pkg/api/testing/codec.go
generated
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright 2017 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 testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mime"
|
||||
"os"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
|
||||
)
|
||||
|
||||
var (
|
||||
testCodecMediaType string
|
||||
testStorageCodecMediaType string
|
||||
)
|
||||
|
||||
// TestCodec returns the codec for the API version to test against, as set by the
|
||||
// KUBE_TEST_API_TYPE env var.
|
||||
func TestCodec(codecs runtimeserializer.CodecFactory, gvs ...schema.GroupVersion) runtime.Codec {
|
||||
if len(testCodecMediaType) != 0 {
|
||||
serializerInfo, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), testCodecMediaType)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("no serializer for %s", testCodecMediaType))
|
||||
}
|
||||
return codecs.CodecForVersions(serializerInfo.Serializer, codecs.UniversalDeserializer(), schema.GroupVersions(gvs), nil)
|
||||
}
|
||||
return codecs.LegacyCodec(gvs...)
|
||||
}
|
||||
|
||||
// TestStorageCodec returns the codec for the API version to test against used in storage, as set by the
|
||||
// KUBE_TEST_API_STORAGE_TYPE env var.
|
||||
func TestStorageCodec(codecs runtimeserializer.CodecFactory, gvs ...schema.GroupVersion) runtime.Codec {
|
||||
if len(testStorageCodecMediaType) != 0 {
|
||||
serializerInfo, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), testStorageCodecMediaType)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("no serializer for %s", testStorageCodecMediaType))
|
||||
}
|
||||
|
||||
// etcd2 only supports string data - we must wrap any result before returning
|
||||
// TODO: remove for etcd3 / make parameterizable
|
||||
serializer := serializerInfo.Serializer
|
||||
if !serializerInfo.EncodesAsText {
|
||||
serializer = runtime.NewBase64Serializer(serializer, serializer)
|
||||
}
|
||||
|
||||
decoder := recognizer.NewDecoder(serializer, codecs.UniversalDeserializer())
|
||||
return codecs.CodecForVersions(serializer, decoder, schema.GroupVersions(gvs), nil)
|
||||
|
||||
}
|
||||
return codecs.LegacyCodec(gvs...)
|
||||
}
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
if apiMediaType := os.Getenv("KUBE_TEST_API_TYPE"); len(apiMediaType) > 0 {
|
||||
testCodecMediaType, _, err = mime.ParseMediaType(apiMediaType)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
if storageMediaType := os.Getenv("KUBE_TEST_API_STORAGE_TYPE"); len(storageMediaType) > 0 {
|
||||
testStorageCodecMediaType, _, err = mime.ParseMediaType(storageMediaType)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
40
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/BUILD
generated
vendored
Normal file
40
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/BUILD
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["valuefuzz_test.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/testing/fuzzer",
|
||||
library = ":go_default_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"fuzzer.go",
|
||||
"valuefuzz.go",
|
||||
],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/testing/fuzzer",
|
||||
deps = [
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
52
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/fuzzer.go
generated
vendored
Normal file
52
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/fuzzer.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 2017 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 fuzzer
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
)
|
||||
|
||||
// FuzzerFuncs returns a list of func(*SomeType, c fuzz.Continue) functions.
|
||||
type FuzzerFuncs func(codecs runtimeserializer.CodecFactory) []interface{}
|
||||
|
||||
// FuzzerFor can randomly populate api objects that are destined for version.
|
||||
func FuzzerFor(funcs FuzzerFuncs, src rand.Source, codecs runtimeserializer.CodecFactory) *fuzz.Fuzzer {
|
||||
f := fuzz.New().NilChance(.5).NumElements(0, 1)
|
||||
if src != nil {
|
||||
f.RandSource(src)
|
||||
}
|
||||
f.Funcs(funcs(codecs)...)
|
||||
return f
|
||||
}
|
||||
|
||||
// MergeFuzzerFuncs will merge the given funcLists, overriding early funcs with later ones if there first
|
||||
// argument has the same type.
|
||||
func MergeFuzzerFuncs(funcs ...FuzzerFuncs) FuzzerFuncs {
|
||||
return FuzzerFuncs(func(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
result := []interface{}{}
|
||||
for _, f := range funcs {
|
||||
if f != nil {
|
||||
result = append(result, f(codecs)...)
|
||||
}
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
86
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/valuefuzz.go
generated
vendored
Normal file
86
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/valuefuzz.go
generated
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright 2017 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 fuzzer
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// ValueFuzz recursively changes all basic type values in an object. Any kind of references will not
|
||||
// be touch, i.e. the addresses of slices, maps, pointers will stay unchanged.
|
||||
func ValueFuzz(obj interface{}) {
|
||||
valueFuzz(reflect.ValueOf(obj))
|
||||
}
|
||||
|
||||
func valueFuzz(obj reflect.Value) {
|
||||
switch obj.Kind() {
|
||||
case reflect.Array:
|
||||
for i := 0; i < obj.Len(); i++ {
|
||||
valueFuzz(obj.Index(i))
|
||||
}
|
||||
case reflect.Slice:
|
||||
if obj.IsNil() {
|
||||
// TODO: set non-nil value
|
||||
} else {
|
||||
for i := 0; i < obj.Len(); i++ {
|
||||
valueFuzz(obj.Index(i))
|
||||
}
|
||||
}
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
if obj.IsNil() {
|
||||
// TODO: set non-nil value
|
||||
} else {
|
||||
valueFuzz(obj.Elem())
|
||||
}
|
||||
case reflect.Struct:
|
||||
for i, n := 0, obj.NumField(); i < n; i++ {
|
||||
valueFuzz(obj.Field(i))
|
||||
}
|
||||
case reflect.Map:
|
||||
if obj.IsNil() {
|
||||
// TODO: set non-nil value
|
||||
} else {
|
||||
for _, k := range obj.MapKeys() {
|
||||
// map values are not addressable. We need a copy.
|
||||
v := obj.MapIndex(k)
|
||||
copy := reflect.New(v.Type())
|
||||
copy.Elem().Set(v)
|
||||
valueFuzz(copy.Elem())
|
||||
obj.SetMapIndex(k, copy.Elem())
|
||||
}
|
||||
// TODO: set some new value
|
||||
}
|
||||
case reflect.Func: // ignore, we don't have function types in our API
|
||||
default:
|
||||
if !obj.CanSet() {
|
||||
return
|
||||
}
|
||||
switch obj.Kind() {
|
||||
case reflect.String:
|
||||
obj.SetString(obj.String() + "x")
|
||||
case reflect.Bool:
|
||||
obj.SetBool(!obj.Bool())
|
||||
case reflect.Float32, reflect.Float64:
|
||||
obj.SetFloat(obj.Float()*2.0 + 1.0)
|
||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
||||
obj.SetInt(obj.Int() + 1)
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||
obj.SetUint(obj.Uint() + 1)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
73
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/valuefuzz_test.go
generated
vendored
Normal file
73
vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer/valuefuzz_test.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright 2017 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 fuzzer
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestValueFuzz(t *testing.T) {
|
||||
type (
|
||||
Y struct {
|
||||
I int
|
||||
B bool
|
||||
F float32
|
||||
U uint
|
||||
}
|
||||
X struct {
|
||||
Ptr *X
|
||||
Y Y
|
||||
Map map[string]int
|
||||
Slice []int
|
||||
}
|
||||
)
|
||||
|
||||
x := X{
|
||||
Ptr: &X{},
|
||||
Map: map[string]int{"foo": 42},
|
||||
Slice: []int{1, 2, 3},
|
||||
}
|
||||
|
||||
p := x.Ptr
|
||||
m := x.Map
|
||||
s := x.Slice
|
||||
|
||||
ValueFuzz(x)
|
||||
|
||||
if x.Ptr.Y.I == 0 {
|
||||
t.Errorf("x.Ptr.Y.I should have changed")
|
||||
}
|
||||
|
||||
if x.Map["foo"] == 42 {
|
||||
t.Errorf("x.Map[foo] should have changed")
|
||||
}
|
||||
|
||||
if x.Slice[0] == 1 {
|
||||
t.Errorf("x.Slice[0] should have changed")
|
||||
}
|
||||
|
||||
if x.Ptr != p {
|
||||
t.Errorf("x.Ptr changed")
|
||||
}
|
||||
|
||||
m["foo"] = 7
|
||||
if x.Map["foo"] != m["foo"] {
|
||||
t.Errorf("x.Map changed")
|
||||
}
|
||||
s[0] = 7
|
||||
if x.Slice[0] != s[0] {
|
||||
t.Errorf("x.Slice changed")
|
||||
}
|
||||
}
|
45
vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip/BUILD
generated
vendored
Normal file
45
vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip/BUILD
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["roundtrip.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/testing/roundtrip",
|
||||
deps = [
|
||||
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
|
||||
"//vendor/github.com/golang/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/testing:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery/announced:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/protobuf:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
409
vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip/roundtrip.go
generated
vendored
Normal file
409
vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip/roundtrip.go
generated
vendored
Normal file
@ -0,0 +1,409 @@
|
||||
/*
|
||||
Copyright 2017 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 roundtrip
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/google/gofuzz"
|
||||
flag "github.com/spf13/pflag"
|
||||
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
apitesting "k8s.io/apimachinery/pkg/api/testing"
|
||||
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
|
||||
"k8s.io/apimachinery/pkg/apimachinery/announced"
|
||||
"k8s.io/apimachinery/pkg/apimachinery/registered"
|
||||
metafuzzer "k8s.io/apimachinery/pkg/apis/meta/fuzzer"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/protobuf"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
type InstallFunc func(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme)
|
||||
|
||||
// RoundTripTestForAPIGroup is convenient to call from your install package to make sure that a "bare" install of your group provides
|
||||
// enough information to round trip
|
||||
func RoundTripTestForAPIGroup(t *testing.T, installFn InstallFunc, fuzzingFuncs fuzzer.FuzzerFuncs) {
|
||||
groupFactoryRegistry := make(announced.APIGroupFactoryRegistry)
|
||||
registry := registered.NewOrDie("")
|
||||
scheme := runtime.NewScheme()
|
||||
installFn(groupFactoryRegistry, registry, scheme)
|
||||
|
||||
RoundTripTestForScheme(t, scheme, fuzzingFuncs)
|
||||
}
|
||||
|
||||
// RoundTripTestForScheme is convenient to call if you already have a scheme and want to make sure that its well-formed
|
||||
func RoundTripTestForScheme(t *testing.T, scheme *runtime.Scheme, fuzzingFuncs fuzzer.FuzzerFuncs) {
|
||||
codecFactory := runtimeserializer.NewCodecFactory(scheme)
|
||||
f := fuzzer.FuzzerFor(
|
||||
fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, fuzzingFuncs),
|
||||
rand.NewSource(rand.Int63()),
|
||||
codecFactory,
|
||||
)
|
||||
RoundTripTypesWithoutProtobuf(t, scheme, codecFactory, f, nil)
|
||||
}
|
||||
|
||||
// RoundTripProtobufTestForAPIGroup is convenient to call from your install package to make sure that a "bare" install of your group provides
|
||||
// enough information to round trip
|
||||
func RoundTripProtobufTestForAPIGroup(t *testing.T, installFn InstallFunc, fuzzingFuncs fuzzer.FuzzerFuncs) {
|
||||
groupFactoryRegistry := make(announced.APIGroupFactoryRegistry)
|
||||
registry := registered.NewOrDie("")
|
||||
scheme := runtime.NewScheme()
|
||||
installFn(groupFactoryRegistry, registry, scheme)
|
||||
|
||||
RoundTripProtobufTestForScheme(t, scheme, fuzzingFuncs)
|
||||
}
|
||||
|
||||
// RoundTripProtobufTestForScheme is convenient to call if you already have a scheme and want to make sure that its well-formed
|
||||
func RoundTripProtobufTestForScheme(t *testing.T, scheme *runtime.Scheme, fuzzingFuncs fuzzer.FuzzerFuncs) {
|
||||
codecFactory := runtimeserializer.NewCodecFactory(scheme)
|
||||
fuzzer := fuzzer.FuzzerFor(
|
||||
fuzzer.MergeFuzzerFuncs(metafuzzer.Funcs, fuzzingFuncs),
|
||||
rand.NewSource(rand.Int63()),
|
||||
codecFactory,
|
||||
)
|
||||
RoundTripTypes(t, scheme, codecFactory, fuzzer, nil)
|
||||
}
|
||||
|
||||
var FuzzIters = flag.Int("fuzz-iters", 20, "How many fuzzing iterations to do.")
|
||||
|
||||
// globalNonRoundTrippableTypes are kinds that are effectively reserved across all GroupVersions
|
||||
// They don't roundtrip
|
||||
var globalNonRoundTrippableTypes = sets.NewString(
|
||||
"ExportOptions",
|
||||
"GetOptions",
|
||||
// WatchEvent does not include kind and version and can only be deserialized
|
||||
// implicitly (if the caller expects the specific object). The watch call defines
|
||||
// the schema by content type, rather than via kind/version included in each
|
||||
// object.
|
||||
"WatchEvent",
|
||||
// ListOptions is now part of the meta group
|
||||
"ListOptions",
|
||||
// Delete options is only read in metav1
|
||||
"DeleteOptions",
|
||||
)
|
||||
|
||||
// RoundTripTypesWithoutProtobuf applies the round-trip test to all round-trippable Kinds
|
||||
// in the scheme. It will skip all the GroupVersionKinds in the skip list.
|
||||
func RoundTripTypesWithoutProtobuf(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
|
||||
roundTripTypes(t, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, true)
|
||||
}
|
||||
|
||||
func RoundTripTypes(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
|
||||
roundTripTypes(t, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, false)
|
||||
}
|
||||
|
||||
func roundTripTypes(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool, skipProtobuf bool) {
|
||||
for _, group := range groupsFromScheme(scheme) {
|
||||
t.Logf("starting group %q", group)
|
||||
internalVersion := schema.GroupVersion{Group: group, Version: runtime.APIVersionInternal}
|
||||
internalKindToGoType := scheme.KnownTypes(internalVersion)
|
||||
|
||||
for kind := range internalKindToGoType {
|
||||
if globalNonRoundTrippableTypes.Has(kind) {
|
||||
continue
|
||||
}
|
||||
|
||||
internalGVK := internalVersion.WithKind(kind)
|
||||
roundTripSpecificKind(t, internalGVK, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, skipProtobuf)
|
||||
}
|
||||
|
||||
t.Logf("finished group %q", group)
|
||||
}
|
||||
}
|
||||
|
||||
func RoundTripSpecificKindWithoutProtobuf(t *testing.T, gvk schema.GroupVersionKind, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
|
||||
roundTripSpecificKind(t, gvk, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, true)
|
||||
}
|
||||
|
||||
func RoundTripSpecificKind(t *testing.T, gvk schema.GroupVersionKind, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool) {
|
||||
roundTripSpecificKind(t, gvk, scheme, codecFactory, fuzzer, nonRoundTrippableTypes, false)
|
||||
}
|
||||
|
||||
func roundTripSpecificKind(t *testing.T, gvk schema.GroupVersionKind, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, nonRoundTrippableTypes map[schema.GroupVersionKind]bool, skipProtobuf bool) {
|
||||
if nonRoundTrippableTypes[gvk] {
|
||||
t.Logf("skipping %v", gvk)
|
||||
return
|
||||
}
|
||||
t.Logf("round tripping %v", gvk)
|
||||
|
||||
// Try a few times, since runTest uses random values.
|
||||
for i := 0; i < *FuzzIters; i++ {
|
||||
if gvk.Version == runtime.APIVersionInternal {
|
||||
roundTripToAllExternalVersions(t, scheme, codecFactory, fuzzer, gvk, nonRoundTrippableTypes, skipProtobuf)
|
||||
} else {
|
||||
roundTripOfExternalType(t, scheme, codecFactory, fuzzer, gvk, skipProtobuf)
|
||||
}
|
||||
if t.Failed() {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fuzzInternalObject fuzzes an arbitrary runtime object using the appropriate
|
||||
// fuzzer registered with the apitesting package.
|
||||
func fuzzInternalObject(t *testing.T, fuzzer *fuzz.Fuzzer, object runtime.Object) runtime.Object {
|
||||
fuzzer.Fuzz(object)
|
||||
|
||||
j, err := apimeta.TypeAccessor(object)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v for %#v", err, object)
|
||||
}
|
||||
j.SetKind("")
|
||||
j.SetAPIVersion("")
|
||||
|
||||
return object
|
||||
}
|
||||
|
||||
func groupsFromScheme(scheme *runtime.Scheme) []string {
|
||||
ret := sets.String{}
|
||||
for gvk := range scheme.AllKnownTypes() {
|
||||
ret.Insert(gvk.Group)
|
||||
}
|
||||
return ret.List()
|
||||
}
|
||||
|
||||
func roundTripToAllExternalVersions(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, internalGVK schema.GroupVersionKind, nonRoundTrippableTypes map[schema.GroupVersionKind]bool, skipProtobuf bool) {
|
||||
object, err := scheme.New(internalGVK)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't make a %v? %v", internalGVK, err)
|
||||
}
|
||||
if _, err := apimeta.TypeAccessor(object); err != nil {
|
||||
t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableInternalTypes: %v", internalGVK, err)
|
||||
}
|
||||
|
||||
fuzzInternalObject(t, fuzzer, object)
|
||||
|
||||
// find all potential serializations in the scheme.
|
||||
// TODO fix this up to handle kinds that cross registered with different names.
|
||||
for externalGVK, externalGoType := range scheme.AllKnownTypes() {
|
||||
if externalGVK.Version == runtime.APIVersionInternal {
|
||||
continue
|
||||
}
|
||||
if externalGVK.GroupKind() != internalGVK.GroupKind() {
|
||||
continue
|
||||
}
|
||||
if nonRoundTrippableTypes[externalGVK] {
|
||||
t.Logf("\tskipping %v %v", externalGVK, externalGoType)
|
||||
continue
|
||||
}
|
||||
t.Logf("\tround tripping to %v %v", externalGVK, externalGoType)
|
||||
|
||||
roundTrip(t, scheme, apitesting.TestCodec(codecFactory, externalGVK.GroupVersion()), object)
|
||||
|
||||
// TODO remove this hack after we're past the intermediate steps
|
||||
if !skipProtobuf && externalGVK.Group != "kubeadm.k8s.io" {
|
||||
s := protobuf.NewSerializer(scheme, scheme, "application/arbitrary.content.type")
|
||||
protobufCodec := codecFactory.CodecForVersions(s, s, externalGVK.GroupVersion(), nil)
|
||||
roundTrip(t, scheme, protobufCodec, object)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func roundTripOfExternalType(t *testing.T, scheme *runtime.Scheme, codecFactory runtimeserializer.CodecFactory, fuzzer *fuzz.Fuzzer, externalGVK schema.GroupVersionKind, skipProtobuf bool) {
|
||||
object, err := scheme.New(externalGVK)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't make a %v? %v", externalGVK, err)
|
||||
}
|
||||
typeAcc, err := apimeta.TypeAccessor(object)
|
||||
if err != nil {
|
||||
t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableInternalTypes: %v", externalGVK, err)
|
||||
}
|
||||
|
||||
fuzzInternalObject(t, fuzzer, object)
|
||||
|
||||
externalGoType := reflect.TypeOf(object).PkgPath()
|
||||
t.Logf("\tround tripping external type %v %v", externalGVK, externalGoType)
|
||||
|
||||
typeAcc.SetKind(externalGVK.Kind)
|
||||
typeAcc.SetAPIVersion(externalGVK.GroupVersion().String())
|
||||
|
||||
roundTrip(t, scheme, json.NewSerializer(json.DefaultMetaFactory, scheme, scheme, false), object)
|
||||
|
||||
// TODO remove this hack after we're past the intermediate steps
|
||||
if !skipProtobuf {
|
||||
roundTrip(t, scheme, protobuf.NewSerializer(scheme, scheme, "application/protobuf"), object)
|
||||
}
|
||||
}
|
||||
|
||||
// roundTrip applies a single round-trip test to the given runtime object
|
||||
// using the given codec. The round-trip test ensures that an object can be
|
||||
// deep-copied, converted, marshaled and back without loss of data.
|
||||
//
|
||||
// For internal types this means
|
||||
//
|
||||
// internal -> external -> json/protobuf -> external -> internal.
|
||||
//
|
||||
// For external types this means
|
||||
//
|
||||
// external -> json/protobuf -> external.
|
||||
func roundTrip(t *testing.T, scheme *runtime.Scheme, codec runtime.Codec, object runtime.Object) {
|
||||
printer := spew.ConfigState{DisableMethods: true}
|
||||
original := object
|
||||
|
||||
// deep copy the original object
|
||||
object = object.DeepCopyObject()
|
||||
name := reflect.TypeOf(object).Elem().Name()
|
||||
if !apiequality.Semantic.DeepEqual(original, object) {
|
||||
t.Errorf("%v: DeepCopy altered the object, diff: %v", name, diff.ObjectReflectDiff(original, object))
|
||||
t.Errorf("%s", spew.Sdump(original))
|
||||
t.Errorf("%s", spew.Sdump(object))
|
||||
return
|
||||
}
|
||||
|
||||
// catch deepcopy errors early
|
||||
if !apiequality.Semantic.DeepEqual(original, object) {
|
||||
t.Errorf("%v: DeepCopy did not lead to equal object, diff: %v", name, diff.ObjectReflectDiff(original, object))
|
||||
return
|
||||
}
|
||||
|
||||
// encode (serialize) the deep copy using the provided codec
|
||||
data, err := runtime.Encode(codec, object)
|
||||
if err != nil {
|
||||
if runtime.IsNotRegisteredError(err) {
|
||||
t.Logf("%v: not registered: %v (%s)", name, err, printer.Sprintf("%#v", object))
|
||||
} else {
|
||||
t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", object))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ensure that the deep copy is equal to the original; neither the deep
|
||||
// copy or conversion should alter the object
|
||||
// TODO eliminate this global
|
||||
if !apiequality.Semantic.DeepEqual(original, object) {
|
||||
t.Errorf("%v: encode altered the object, diff: %v", name, diff.ObjectReflectDiff(original, object))
|
||||
return
|
||||
}
|
||||
|
||||
// encode (serialize) a second time to verify that it was not varying
|
||||
secondData, err := runtime.Encode(codec, object)
|
||||
if err != nil {
|
||||
if runtime.IsNotRegisteredError(err) {
|
||||
t.Logf("%v: not registered: %v (%s)", name, err, printer.Sprintf("%#v", object))
|
||||
} else {
|
||||
t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", object))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// serialization to the wire must be stable to ensure that we don't write twice to the DB
|
||||
// when the object hasn't changed.
|
||||
if !bytes.Equal(data, secondData) {
|
||||
t.Errorf("%v: serialization is not stable: %s", name, printer.Sprintf("%#v", object))
|
||||
}
|
||||
|
||||
// decode (deserialize) the encoded data back into an object
|
||||
obj2, err := runtime.Decode(codec, data)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v\nCodec: %#v\nData: %s\nSource: %#v", name, err, codec, dataAsString(data), printer.Sprintf("%#v", object))
|
||||
panic("failed")
|
||||
}
|
||||
|
||||
// ensure that the object produced from decoding the encoded data is equal
|
||||
// to the original object
|
||||
if !apiequality.Semantic.DeepEqual(original, obj2) {
|
||||
t.Errorf("%v: diff: %v\nCodec: %#v\nSource:\n\n%#v\n\nEncoded:\n\n%s\n\nFinal:\n\n%#v", name, diff.ObjectReflectDiff(original, obj2), codec, printer.Sprintf("%#v", original), dataAsString(data), printer.Sprintf("%#v", obj2))
|
||||
return
|
||||
}
|
||||
|
||||
// decode the encoded data into a new object (instead of letting the codec
|
||||
// create a new object)
|
||||
obj3 := reflect.New(reflect.TypeOf(object).Elem()).Interface().(runtime.Object)
|
||||
if err := runtime.DecodeInto(codec, data, obj3); err != nil {
|
||||
t.Errorf("%v: %v", name, err)
|
||||
return
|
||||
}
|
||||
|
||||
// special case for kinds which are internal and external at the same time (many in meta.k8s.io are). For those
|
||||
// runtime.DecodeInto above will return the external variant and set the APIVersion and kind, while the input
|
||||
// object might be internal. Hence, we clear those values for obj3 for that case to correctly compare.
|
||||
intAndExt, err := internalAndExternalKind(scheme, object)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v", name, err)
|
||||
return
|
||||
}
|
||||
if intAndExt {
|
||||
typeAcc, err := apimeta.TypeAccessor(object)
|
||||
if err != nil {
|
||||
t.Fatalf("%v: error accessing TypeMeta: %v", name, err)
|
||||
}
|
||||
if len(typeAcc.GetAPIVersion()) == 0 {
|
||||
typeAcc, err := apimeta.TypeAccessor(obj3)
|
||||
if err != nil {
|
||||
t.Fatalf("%v: error accessing TypeMeta: %v", name, err)
|
||||
}
|
||||
typeAcc.SetAPIVersion("")
|
||||
typeAcc.SetKind("")
|
||||
}
|
||||
}
|
||||
|
||||
// ensure that the new runtime object is equal to the original after being
|
||||
// decoded into
|
||||
if !apiequality.Semantic.DeepEqual(object, obj3) {
|
||||
t.Errorf("%v: diff: %v\nCodec: %#v", name, diff.ObjectReflectDiff(object, obj3), codec)
|
||||
return
|
||||
}
|
||||
|
||||
// do structure-preserving fuzzing of the deep-copied object. If it shares anything with the original,
|
||||
// the deep-copy was actually only a shallow copy. Then original and obj3 will be different after fuzzing.
|
||||
// NOTE: we use the encoding+decoding here as an alternative, guaranteed deep-copy to compare against.
|
||||
fuzzer.ValueFuzz(object)
|
||||
if !apiequality.Semantic.DeepEqual(original, obj3) {
|
||||
t.Errorf("%v: fuzzing a copy altered the original, diff: %v", name, diff.ObjectReflectDiff(original, obj3))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func internalAndExternalKind(scheme *runtime.Scheme, object runtime.Object) (bool, error) {
|
||||
kinds, _, err := scheme.ObjectKinds(object)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
internal, external := false, false
|
||||
for _, k := range kinds {
|
||||
if k.Version == runtime.APIVersionInternal {
|
||||
internal = true
|
||||
} else {
|
||||
external = true
|
||||
}
|
||||
}
|
||||
return internal && external, nil
|
||||
}
|
||||
|
||||
// dataAsString returns the given byte array as a string; handles detecting
|
||||
// protocol buffers.
|
||||
func dataAsString(data []byte) string {
|
||||
dataString := string(data)
|
||||
if !strings.HasPrefix(dataString, "{") {
|
||||
dataString = "\n" + hex.Dump(data)
|
||||
proto.NewBuffer(make([]byte, 0, 1024)).DebugPrint("decoded object", data)
|
||||
}
|
||||
return dataString
|
||||
}
|
54
vendor/k8s.io/apimachinery/pkg/api/validation/BUILD
generated
vendored
Normal file
54
vendor/k8s.io/apimachinery/pkg/api/validation/BUILD
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["objectmeta_test.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/validation",
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"generic.go",
|
||||
"objectmeta.go",
|
||||
],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/validation",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/validation/path:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
18
vendor/k8s.io/apimachinery/pkg/api/validation/doc.go
generated
vendored
Normal file
18
vendor/k8s.io/apimachinery/pkg/api/validation/doc.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright 2017 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 validation contains generic api type validation functions.
|
||||
package validation // import "k8s.io/apimachinery/pkg/api/validation"
|
85
vendor/k8s.io/apimachinery/pkg/api/validation/generic.go
generated
vendored
Normal file
85
vendor/k8s.io/apimachinery/pkg/api/validation/generic.go
generated
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright 2014 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 validation
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
const IsNegativeErrorMsg string = `must be greater than or equal to 0`
|
||||
|
||||
// ValidateNameFunc validates that the provided name is valid for a given resource type.
|
||||
// Not all resources have the same validation rules for names. Prefix is true
|
||||
// if the name will have a value appended to it. If the name is not valid,
|
||||
// this returns a list of descriptions of individual characteristics of the
|
||||
// value that were not valid. Otherwise this returns an empty list or nil.
|
||||
type ValidateNameFunc func(name string, prefix bool) []string
|
||||
|
||||
// NameIsDNSSubdomain is a ValidateNameFunc for names that must be a DNS subdomain.
|
||||
func NameIsDNSSubdomain(name string, prefix bool) []string {
|
||||
if prefix {
|
||||
name = maskTrailingDash(name)
|
||||
}
|
||||
return validation.IsDNS1123Subdomain(name)
|
||||
}
|
||||
|
||||
// NameIsDNSLabel is a ValidateNameFunc for names that must be a DNS 1123 label.
|
||||
func NameIsDNSLabel(name string, prefix bool) []string {
|
||||
if prefix {
|
||||
name = maskTrailingDash(name)
|
||||
}
|
||||
return validation.IsDNS1123Label(name)
|
||||
}
|
||||
|
||||
// NameIsDNS1035Label is a ValidateNameFunc for names that must be a DNS 952 label.
|
||||
func NameIsDNS1035Label(name string, prefix bool) []string {
|
||||
if prefix {
|
||||
name = maskTrailingDash(name)
|
||||
}
|
||||
return validation.IsDNS1035Label(name)
|
||||
}
|
||||
|
||||
// ValidateNamespaceName can be used to check whether the given namespace name is valid.
|
||||
// Prefix indicates this name will be used as part of generation, in which case
|
||||
// trailing dashes are allowed.
|
||||
var ValidateNamespaceName = NameIsDNSLabel
|
||||
|
||||
// ValidateServiceAccountName can be used to check whether the given service account name is valid.
|
||||
// Prefix indicates this name will be used as part of generation, in which case
|
||||
// trailing dashes are allowed.
|
||||
var ValidateServiceAccountName = NameIsDNSSubdomain
|
||||
|
||||
// maskTrailingDash replaces the final character of a string with a subdomain safe
|
||||
// value if is a dash.
|
||||
func maskTrailingDash(name string) string {
|
||||
if strings.HasSuffix(name, "-") {
|
||||
return name[:len(name)-2] + "a"
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// Validates that given value is not negative.
|
||||
func ValidateNonnegativeField(value int64, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if value < 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, value, IsNegativeErrorMsg))
|
||||
}
|
||||
return allErrs
|
||||
}
|
343
vendor/k8s.io/apimachinery/pkg/api/validation/objectmeta.go
generated
vendored
Normal file
343
vendor/k8s.io/apimachinery/pkg/api/validation/objectmeta.go
generated
vendored
Normal file
@ -0,0 +1,343 @@
|
||||
/*
|
||||
Copyright 2014 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 validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
// TODO: delete this global variable when we enable the validation of common
|
||||
// fields by default.
|
||||
var RepairMalformedUpdates bool = true
|
||||
|
||||
const FieldImmutableErrorMsg string = `field is immutable`
|
||||
|
||||
const totalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB
|
||||
|
||||
// BannedOwners is a black list of object that are not allowed to be owners.
|
||||
var BannedOwners = map[schema.GroupVersionKind]struct{}{
|
||||
{Group: "", Version: "v1", Kind: "Event"}: {},
|
||||
}
|
||||
|
||||
// ValidateClusterName can be used to check whether the given cluster name is valid.
|
||||
var ValidateClusterName = NameIsDNS1035Label
|
||||
|
||||
// ValidateAnnotations validates that a set of annotations are correctly defined.
|
||||
func ValidateAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
var totalSize int64
|
||||
for k, v := range annotations {
|
||||
for _, msg := range validation.IsQualifiedName(strings.ToLower(k)) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, k, msg))
|
||||
}
|
||||
totalSize += (int64)(len(k)) + (int64)(len(v))
|
||||
}
|
||||
if totalSize > (int64)(totalAnnotationSizeLimitB) {
|
||||
allErrs = append(allErrs, field.TooLong(fldPath, "", totalAnnotationSizeLimitB))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateOwnerReference(ownerReference metav1.OwnerReference, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
gvk := schema.FromAPIVersionAndKind(ownerReference.APIVersion, ownerReference.Kind)
|
||||
// gvk.Group is empty for the legacy group.
|
||||
if len(gvk.Version) == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("apiVersion"), ownerReference.APIVersion, "version must not be empty"))
|
||||
}
|
||||
if len(gvk.Kind) == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("kind"), ownerReference.Kind, "kind must not be empty"))
|
||||
}
|
||||
if len(ownerReference.Name) == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), ownerReference.Name, "name must not be empty"))
|
||||
}
|
||||
if len(ownerReference.UID) == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("uid"), ownerReference.UID, "uid must not be empty"))
|
||||
}
|
||||
if _, ok := BannedOwners[gvk]; ok {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, ownerReference, fmt.Sprintf("%s is disallowed from being an owner", gvk)))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidateOwnerReferences(ownerReferences []metav1.OwnerReference, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
controllerName := ""
|
||||
for _, ref := range ownerReferences {
|
||||
allErrs = append(allErrs, validateOwnerReference(ref, fldPath)...)
|
||||
if ref.Controller != nil && *ref.Controller {
|
||||
if controllerName != "" {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, ownerReferences,
|
||||
fmt.Sprintf("Only one reference can have Controller set to true. Found \"true\" in references for %v and %v", controllerName, ref.Name)))
|
||||
} else {
|
||||
controllerName = ref.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// Validate finalizer names
|
||||
func ValidateFinalizerName(stringValue string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
for _, msg := range validation.IsQualifiedName(stringValue) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, stringValue, msg))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidateNoNewFinalizers(newFinalizers []string, oldFinalizers []string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
extra := sets.NewString(newFinalizers...).Difference(sets.NewString(oldFinalizers...))
|
||||
if len(extra) != 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath, fmt.Sprintf("no new finalizers can be added if the object is being deleted, found new finalizers %#v", extra.List())))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidateImmutableField(newVal, oldVal interface{}, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if !apiequality.Semantic.DeepEqual(oldVal, newVal) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, newVal, FieldImmutableErrorMsg))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateObjectMeta validates an object's metadata on creation. It expects that name generation has already
|
||||
// been performed.
|
||||
// It doesn't return an error for rootscoped resources with namespace, because namespace should already be cleared before.
|
||||
func ValidateObjectMeta(objMeta *metav1.ObjectMeta, requiresNamespace bool, nameFn ValidateNameFunc, fldPath *field.Path) field.ErrorList {
|
||||
metadata, err := meta.Accessor(objMeta)
|
||||
if err != nil {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, objMeta, err.Error()))
|
||||
return allErrs
|
||||
}
|
||||
return ValidateObjectMetaAccessor(metadata, requiresNamespace, nameFn, fldPath)
|
||||
}
|
||||
|
||||
// ValidateObjectMeta validates an object's metadata on creation. It expects that name generation has already
|
||||
// been performed.
|
||||
// It doesn't return an error for rootscoped resources with namespace, because namespace should already be cleared before.
|
||||
func ValidateObjectMetaAccessor(meta metav1.Object, requiresNamespace bool, nameFn ValidateNameFunc, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if len(meta.GetGenerateName()) != 0 {
|
||||
for _, msg := range nameFn(meta.GetGenerateName(), true) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("generateName"), meta.GetGenerateName(), msg))
|
||||
}
|
||||
}
|
||||
// If the generated name validates, but the calculated value does not, it's a problem with generation, and we
|
||||
// report it here. This may confuse users, but indicates a programming bug and still must be validated.
|
||||
// If there are multiple fields out of which one is required then add an or as a separator
|
||||
if len(meta.GetName()) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("name"), "name or generateName is required"))
|
||||
} else {
|
||||
for _, msg := range nameFn(meta.GetName(), false) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), meta.GetName(), msg))
|
||||
}
|
||||
}
|
||||
if requiresNamespace {
|
||||
if len(meta.GetNamespace()) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("namespace"), ""))
|
||||
} else {
|
||||
for _, msg := range ValidateNamespaceName(meta.GetNamespace(), false) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), meta.GetNamespace(), msg))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if len(meta.GetNamespace()) != 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("namespace"), "not allowed on this type"))
|
||||
}
|
||||
}
|
||||
if len(meta.GetClusterName()) != 0 {
|
||||
for _, msg := range ValidateClusterName(meta.GetClusterName(), false) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("clusterName"), meta.GetClusterName(), msg))
|
||||
}
|
||||
}
|
||||
allErrs = append(allErrs, ValidateNonnegativeField(meta.GetGeneration(), fldPath.Child("generation"))...)
|
||||
allErrs = append(allErrs, v1validation.ValidateLabels(meta.GetLabels(), fldPath.Child("labels"))...)
|
||||
allErrs = append(allErrs, ValidateAnnotations(meta.GetAnnotations(), fldPath.Child("annotations"))...)
|
||||
allErrs = append(allErrs, ValidateOwnerReferences(meta.GetOwnerReferences(), fldPath.Child("ownerReferences"))...)
|
||||
allErrs = append(allErrs, ValidateInitializers(meta.GetInitializers(), fldPath.Child("initializers"))...)
|
||||
allErrs = append(allErrs, ValidateFinalizers(meta.GetFinalizers(), fldPath.Child("finalizers"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidateInitializers(initializers *metav1.Initializers, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
if initializers == nil {
|
||||
return allErrs
|
||||
}
|
||||
for i, initializer := range initializers.Pending {
|
||||
allErrs = append(allErrs, validation.IsFullyQualifiedName(fldPath.Child("pending").Index(i).Child("name"), initializer.Name)...)
|
||||
}
|
||||
allErrs = append(allErrs, validateInitializersResult(initializers.Result, fldPath.Child("result"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateInitializersResult(result *metav1.Status, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
if result == nil {
|
||||
return allErrs
|
||||
}
|
||||
switch result.Status {
|
||||
case metav1.StatusFailure:
|
||||
default:
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("status"), result.Status, "must be 'Failure'"))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateFinalizers tests if the finalizers name are valid, and if there are conflicting finalizers.
|
||||
func ValidateFinalizers(finalizers []string, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
hasFinalizerOrphanDependents := false
|
||||
hasFinalizerDeleteDependents := false
|
||||
for _, finalizer := range finalizers {
|
||||
allErrs = append(allErrs, ValidateFinalizerName(finalizer, fldPath)...)
|
||||
if finalizer == metav1.FinalizerOrphanDependents {
|
||||
hasFinalizerOrphanDependents = true
|
||||
}
|
||||
if finalizer == metav1.FinalizerDeleteDependents {
|
||||
hasFinalizerDeleteDependents = true
|
||||
}
|
||||
}
|
||||
if hasFinalizerDeleteDependents && hasFinalizerOrphanDependents {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, finalizers, fmt.Sprintf("finalizer %s and %s cannot be both set", metav1.FinalizerOrphanDependents, metav1.FinalizerDeleteDependents)))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateObjectMetaUpdate validates an object's metadata when updated
|
||||
func ValidateObjectMetaUpdate(newMeta, oldMeta *metav1.ObjectMeta, fldPath *field.Path) field.ErrorList {
|
||||
newMetadata, err := meta.Accessor(newMeta)
|
||||
if err != nil {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, newMeta, err.Error()))
|
||||
return allErrs
|
||||
}
|
||||
oldMetadata, err := meta.Accessor(oldMeta)
|
||||
if err != nil {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, oldMeta, err.Error()))
|
||||
return allErrs
|
||||
}
|
||||
return ValidateObjectMetaAccessorUpdate(newMetadata, oldMetadata, fldPath)
|
||||
}
|
||||
|
||||
func ValidateObjectMetaAccessorUpdate(newMeta, oldMeta metav1.Object, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
if !RepairMalformedUpdates && newMeta.GetUID() != oldMeta.GetUID() {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("uid"), newMeta.GetUID(), "field is immutable"))
|
||||
}
|
||||
// in the event it is left empty, set it, to allow clients more flexibility
|
||||
// TODO: remove the following code that repairs the update request when we retire the clients that modify the immutable fields.
|
||||
// Please do not copy this pattern elsewhere; validation functions should not be modifying the objects they are passed!
|
||||
if RepairMalformedUpdates {
|
||||
if len(newMeta.GetUID()) == 0 {
|
||||
newMeta.SetUID(oldMeta.GetUID())
|
||||
}
|
||||
// ignore changes to timestamp
|
||||
if oldCreationTime := oldMeta.GetCreationTimestamp(); oldCreationTime.IsZero() {
|
||||
oldMeta.SetCreationTimestamp(newMeta.GetCreationTimestamp())
|
||||
} else {
|
||||
newMeta.SetCreationTimestamp(oldMeta.GetCreationTimestamp())
|
||||
}
|
||||
// an object can never remove a deletion timestamp or clear/change grace period seconds
|
||||
if !oldMeta.GetDeletionTimestamp().IsZero() {
|
||||
newMeta.SetDeletionTimestamp(oldMeta.GetDeletionTimestamp())
|
||||
}
|
||||
if oldMeta.GetDeletionGracePeriodSeconds() != nil && newMeta.GetDeletionGracePeriodSeconds() == nil {
|
||||
newMeta.SetDeletionGracePeriodSeconds(oldMeta.GetDeletionGracePeriodSeconds())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: needs to check if newMeta==nil && oldMeta !=nil after the repair logic is removed.
|
||||
if newMeta.GetDeletionGracePeriodSeconds() != nil && (oldMeta.GetDeletionGracePeriodSeconds() == nil || *newMeta.GetDeletionGracePeriodSeconds() != *oldMeta.GetDeletionGracePeriodSeconds()) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("deletionGracePeriodSeconds"), newMeta.GetDeletionGracePeriodSeconds(), "field is immutable; may only be changed via deletion"))
|
||||
}
|
||||
if newMeta.GetDeletionTimestamp() != nil && (oldMeta.GetDeletionTimestamp() == nil || !newMeta.GetDeletionTimestamp().Equal(oldMeta.GetDeletionTimestamp())) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("deletionTimestamp"), newMeta.GetDeletionTimestamp(), "field is immutable; may only be changed via deletion"))
|
||||
}
|
||||
|
||||
// Finalizers cannot be added if the object is already being deleted.
|
||||
if oldMeta.GetDeletionTimestamp() != nil {
|
||||
allErrs = append(allErrs, ValidateNoNewFinalizers(newMeta.GetFinalizers(), oldMeta.GetFinalizers(), fldPath.Child("finalizers"))...)
|
||||
}
|
||||
|
||||
// Reject updates that don't specify a resource version
|
||||
if len(newMeta.GetResourceVersion()) == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceVersion"), newMeta.GetResourceVersion(), "must be specified for an update"))
|
||||
}
|
||||
|
||||
// Generation shouldn't be decremented
|
||||
if newMeta.GetGeneration() < oldMeta.GetGeneration() {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("generation"), newMeta.GetGeneration(), "must not be decremented"))
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, ValidateInitializersUpdate(newMeta.GetInitializers(), oldMeta.GetInitializers(), fldPath.Child("initializers"))...)
|
||||
|
||||
allErrs = append(allErrs, ValidateImmutableField(newMeta.GetName(), oldMeta.GetName(), fldPath.Child("name"))...)
|
||||
allErrs = append(allErrs, ValidateImmutableField(newMeta.GetNamespace(), oldMeta.GetNamespace(), fldPath.Child("namespace"))...)
|
||||
allErrs = append(allErrs, ValidateImmutableField(newMeta.GetUID(), oldMeta.GetUID(), fldPath.Child("uid"))...)
|
||||
allErrs = append(allErrs, ValidateImmutableField(newMeta.GetCreationTimestamp(), oldMeta.GetCreationTimestamp(), fldPath.Child("creationTimestamp"))...)
|
||||
allErrs = append(allErrs, ValidateImmutableField(newMeta.GetClusterName(), oldMeta.GetClusterName(), fldPath.Child("clusterName"))...)
|
||||
|
||||
allErrs = append(allErrs, v1validation.ValidateLabels(newMeta.GetLabels(), fldPath.Child("labels"))...)
|
||||
allErrs = append(allErrs, ValidateAnnotations(newMeta.GetAnnotations(), fldPath.Child("annotations"))...)
|
||||
allErrs = append(allErrs, ValidateOwnerReferences(newMeta.GetOwnerReferences(), fldPath.Child("ownerReferences"))...)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateInitializersUpdate checks the update of the metadata initializers field
|
||||
func ValidateInitializersUpdate(newInit, oldInit *metav1.Initializers, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
switch {
|
||||
case oldInit == nil && newInit != nil:
|
||||
// Initializers may not be set on new objects
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, nil, "field is immutable once initialization has completed"))
|
||||
case oldInit != nil && newInit == nil:
|
||||
// this is a valid transition and means initialization was successful
|
||||
case oldInit != nil && newInit != nil:
|
||||
// validate changes to initializers
|
||||
switch {
|
||||
case oldInit.Result == nil && newInit.Result != nil:
|
||||
// setting a result is allowed
|
||||
allErrs = append(allErrs, validateInitializersResult(newInit.Result, fldPath.Child("result"))...)
|
||||
case oldInit.Result != nil:
|
||||
// setting Result implies permanent failure, and all future updates will be prevented
|
||||
allErrs = append(allErrs, ValidateImmutableField(newInit.Result, oldInit.Result, fldPath.Child("result"))...)
|
||||
default:
|
||||
// leaving the result nil is allowed
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
500
vendor/k8s.io/apimachinery/pkg/api/validation/objectmeta_test.go
generated
vendored
Normal file
500
vendor/k8s.io/apimachinery/pkg/api/validation/objectmeta_test.go
generated
vendored
Normal file
@ -0,0 +1,500 @@
|
||||
/*
|
||||
Copyright 2017 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 validation
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
const (
|
||||
maxLengthErrMsg = "must be no more than"
|
||||
namePartErrMsg = "name part must consist of"
|
||||
nameErrMsg = "a qualified name must consist of"
|
||||
)
|
||||
|
||||
// Ensure custom name functions are allowed
|
||||
func TestValidateObjectMetaCustomName(t *testing.T) {
|
||||
errs := ValidateObjectMeta(
|
||||
&metav1.ObjectMeta{Name: "test", GenerateName: "foo"},
|
||||
false,
|
||||
func(s string, prefix bool) []string {
|
||||
if s == "test" {
|
||||
return nil
|
||||
}
|
||||
return []string{"name-gen"}
|
||||
},
|
||||
field.NewPath("field"))
|
||||
if len(errs) != 1 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
if !strings.Contains(errs[0].Error(), "name-gen") {
|
||||
t.Errorf("unexpected error message: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure namespace names follow dns label format
|
||||
func TestValidateObjectMetaNamespaces(t *testing.T) {
|
||||
errs := ValidateObjectMeta(
|
||||
&metav1.ObjectMeta{Name: "test", Namespace: "foo.bar"},
|
||||
true,
|
||||
func(s string, prefix bool) []string {
|
||||
return nil
|
||||
},
|
||||
field.NewPath("field"))
|
||||
if len(errs) != 1 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
if !strings.Contains(errs[0].Error(), `Invalid value: "foo.bar"`) {
|
||||
t.Errorf("unexpected error message: %v", errs)
|
||||
}
|
||||
maxLength := 63
|
||||
letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
||||
b := make([]rune, maxLength+1)
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
errs = ValidateObjectMeta(
|
||||
&metav1.ObjectMeta{Name: "test", Namespace: string(b)},
|
||||
true,
|
||||
func(s string, prefix bool) []string {
|
||||
return nil
|
||||
},
|
||||
field.NewPath("field"))
|
||||
if len(errs) != 2 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
if !strings.Contains(errs[0].Error(), "Invalid value") || !strings.Contains(errs[1].Error(), "Invalid value") {
|
||||
t.Errorf("unexpected error message: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateObjectMetaOwnerReferences(t *testing.T) {
|
||||
trueVar := true
|
||||
falseVar := false
|
||||
testCases := []struct {
|
||||
description string
|
||||
ownerReferences []metav1.OwnerReference
|
||||
expectError bool
|
||||
expectedErrorMessage string
|
||||
}{
|
||||
{
|
||||
description: "simple success - third party extension.",
|
||||
ownerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "1",
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
expectedErrorMessage: "",
|
||||
},
|
||||
{
|
||||
description: "simple failures - event shouldn't be set as an owner",
|
||||
ownerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: "v1",
|
||||
Kind: "Event",
|
||||
Name: "name",
|
||||
UID: "1",
|
||||
},
|
||||
},
|
||||
expectError: true,
|
||||
expectedErrorMessage: "is disallowed from being an owner",
|
||||
},
|
||||
{
|
||||
description: "simple controller ref success - one reference with Controller set",
|
||||
ownerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "1",
|
||||
Controller: &falseVar,
|
||||
},
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "2",
|
||||
Controller: &trueVar,
|
||||
},
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "3",
|
||||
Controller: &falseVar,
|
||||
},
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "4",
|
||||
},
|
||||
},
|
||||
expectError: false,
|
||||
expectedErrorMessage: "",
|
||||
},
|
||||
{
|
||||
description: "simple controller ref failure - two references with Controller set",
|
||||
ownerReferences: []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "1",
|
||||
Controller: &falseVar,
|
||||
},
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "2",
|
||||
Controller: &trueVar,
|
||||
},
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "3",
|
||||
Controller: &trueVar,
|
||||
},
|
||||
{
|
||||
APIVersion: "customresourceVersion",
|
||||
Kind: "customresourceKind",
|
||||
Name: "name",
|
||||
UID: "4",
|
||||
},
|
||||
},
|
||||
expectError: true,
|
||||
expectedErrorMessage: "Only one reference can have Controller set to true",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
errs := ValidateObjectMeta(
|
||||
&metav1.ObjectMeta{Name: "test", Namespace: "test", OwnerReferences: tc.ownerReferences},
|
||||
true,
|
||||
func(s string, prefix bool) []string {
|
||||
return nil
|
||||
},
|
||||
field.NewPath("field"))
|
||||
if len(errs) != 0 && !tc.expectError {
|
||||
t.Errorf("unexpected error: %v in test case %v", errs, tc.description)
|
||||
}
|
||||
if len(errs) == 0 && tc.expectError {
|
||||
t.Errorf("expect error in test case %v", tc.description)
|
||||
}
|
||||
if len(errs) != 0 && !strings.Contains(errs[0].Error(), tc.expectedErrorMessage) {
|
||||
t.Errorf("unexpected error message: %v in test case %v", errs, tc.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateObjectMetaUpdateIgnoresCreationTimestamp(t *testing.T) {
|
||||
if errs := ValidateObjectMetaUpdate(
|
||||
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(10, 0))},
|
||||
field.NewPath("field"),
|
||||
); len(errs) != 0 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
if errs := ValidateObjectMetaUpdate(
|
||||
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(10, 0))},
|
||||
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
field.NewPath("field"),
|
||||
); len(errs) != 0 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
if errs := ValidateObjectMetaUpdate(
|
||||
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(10, 0))},
|
||||
&metav1.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: metav1.NewTime(time.Unix(11, 0))},
|
||||
field.NewPath("field"),
|
||||
); len(errs) != 0 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateFinalizersUpdate(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
Old metav1.ObjectMeta
|
||||
New metav1.ObjectMeta
|
||||
ExpectedErr string
|
||||
}{
|
||||
"invalid adding finalizers": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a"}},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a", "y/b"}},
|
||||
ExpectedErr: "y/b",
|
||||
},
|
||||
"invalid changing finalizers": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a"}},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/b"}},
|
||||
ExpectedErr: "x/b",
|
||||
},
|
||||
"valid removing finalizers": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a", "y/b"}},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &metav1.Time{}, Finalizers: []string{"x/a"}},
|
||||
ExpectedErr: "",
|
||||
},
|
||||
"valid adding finalizers for objects not being deleted": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Finalizers: []string{"x/a"}},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Finalizers: []string{"x/a", "y/b"}},
|
||||
ExpectedErr: "",
|
||||
},
|
||||
}
|
||||
for name, tc := range testcases {
|
||||
errs := ValidateObjectMetaUpdate(&tc.New, &tc.Old, field.NewPath("field"))
|
||||
if len(errs) == 0 {
|
||||
if len(tc.ExpectedErr) != 0 {
|
||||
t.Errorf("case: %q, expected error to contain %q", name, tc.ExpectedErr)
|
||||
}
|
||||
} else if e, a := tc.ExpectedErr, errs.ToAggregate().Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("case: %q, expected error to contain %q, got error %q", name, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateFinalizersPreventConflictingFinalizers(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
ObjectMeta metav1.ObjectMeta
|
||||
ExpectedErr string
|
||||
}{
|
||||
"conflicting finalizers": {
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Finalizers: []string{metav1.FinalizerOrphanDependents, metav1.FinalizerDeleteDependents}},
|
||||
ExpectedErr: "cannot be both set",
|
||||
},
|
||||
}
|
||||
for name, tc := range testcases {
|
||||
errs := ValidateObjectMeta(&tc.ObjectMeta, false, NameIsDNSSubdomain, field.NewPath("field"))
|
||||
if len(errs) == 0 {
|
||||
if len(tc.ExpectedErr) != 0 {
|
||||
t.Errorf("case: %q, expected error to contain %q", name, tc.ExpectedErr)
|
||||
}
|
||||
} else if e, a := tc.ExpectedErr, errs.ToAggregate().Error(); !strings.Contains(a, e) {
|
||||
t.Errorf("case: %q, expected error to contain %q, got error %q", name, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateObjectMetaUpdatePreventsDeletionFieldMutation(t *testing.T) {
|
||||
now := metav1.NewTime(time.Unix(1000, 0).UTC())
|
||||
later := metav1.NewTime(time.Unix(2000, 0).UTC())
|
||||
gracePeriodShort := int64(30)
|
||||
gracePeriodLong := int64(40)
|
||||
|
||||
testcases := map[string]struct {
|
||||
Old metav1.ObjectMeta
|
||||
New metav1.ObjectMeta
|
||||
ExpectedNew metav1.ObjectMeta
|
||||
ExpectedErrs []string
|
||||
}{
|
||||
"valid without deletion fields": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
ExpectedErrs: []string{},
|
||||
},
|
||||
"valid with deletion fields": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now, DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now, DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now, DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
ExpectedErrs: []string{},
|
||||
},
|
||||
|
||||
"invalid set deletionTimestamp": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||
ExpectedErrs: []string{"field.deletionTimestamp: Invalid value: 1970-01-01 00:16:40 +0000 UTC: field is immutable; may only be changed via deletion"},
|
||||
},
|
||||
"invalid clear deletionTimestamp": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||
ExpectedErrs: []string{}, // no errors, validation copies the old value
|
||||
},
|
||||
"invalid change deletionTimestamp": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &later},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||
ExpectedErrs: []string{}, // no errors, validation copies the old value
|
||||
},
|
||||
|
||||
"invalid set deletionGracePeriodSeconds": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
ExpectedErrs: []string{"field.deletionGracePeriodSeconds: Invalid value: 30: field is immutable; may only be changed via deletion"},
|
||||
},
|
||||
"invalid clear deletionGracePeriodSeconds": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
ExpectedErrs: []string{}, // no errors, validation copies the old value
|
||||
},
|
||||
"invalid change deletionGracePeriodSeconds": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodShort},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodLong},
|
||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionGracePeriodSeconds: &gracePeriodLong},
|
||||
ExpectedErrs: []string{"field.deletionGracePeriodSeconds: Invalid value: 40: field is immutable; may only be changed via deletion"},
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range testcases {
|
||||
errs := ValidateObjectMetaUpdate(&tc.New, &tc.Old, field.NewPath("field"))
|
||||
if len(errs) != len(tc.ExpectedErrs) {
|
||||
t.Logf("%s: Expected: %#v", k, tc.ExpectedErrs)
|
||||
t.Logf("%s: Got: %#v", k, errs)
|
||||
t.Errorf("%s: expected %d errors, got %d", k, len(tc.ExpectedErrs), len(errs))
|
||||
continue
|
||||
}
|
||||
for i := range errs {
|
||||
if errs[i].Error() != tc.ExpectedErrs[i] {
|
||||
t.Errorf("%s: error #%d: expected %q, got %q", k, i, tc.ExpectedErrs[i], errs[i].Error())
|
||||
}
|
||||
}
|
||||
if !reflect.DeepEqual(tc.New, tc.ExpectedNew) {
|
||||
t.Errorf("%s: Expected after validation:\n%#v\ngot\n%#v", k, tc.ExpectedNew, tc.New)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestObjectMetaGenerationUpdate(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
Old metav1.ObjectMeta
|
||||
New metav1.ObjectMeta
|
||||
ExpectedErrs []string
|
||||
}{
|
||||
"invalid generation change - decremented": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 5},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 4},
|
||||
ExpectedErrs: []string{"field.generation: Invalid value: 4: must not be decremented"},
|
||||
},
|
||||
"valid generation change - incremented by one": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 1},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 2},
|
||||
ExpectedErrs: []string{},
|
||||
},
|
||||
"valid generation field - not updated": {
|
||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 5},
|
||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", Generation: 5},
|
||||
ExpectedErrs: []string{},
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range testcases {
|
||||
errList := []string{}
|
||||
errs := ValidateObjectMetaUpdate(&tc.New, &tc.Old, field.NewPath("field"))
|
||||
if len(errs) != len(tc.ExpectedErrs) {
|
||||
t.Logf("%s: Expected: %#v", k, tc.ExpectedErrs)
|
||||
for _, err := range errs {
|
||||
errList = append(errList, err.Error())
|
||||
}
|
||||
t.Logf("%s: Got: %#v", k, errList)
|
||||
t.Errorf("%s: expected %d errors, got %d", k, len(tc.ExpectedErrs), len(errs))
|
||||
continue
|
||||
}
|
||||
for i := range errList {
|
||||
if errList[i] != tc.ExpectedErrs[i] {
|
||||
t.Errorf("%s: error #%d: expected %q, got %q", k, i, tc.ExpectedErrs[i], errList[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure trailing slash is allowed in generate name
|
||||
func TestValidateObjectMetaTrimsTrailingSlash(t *testing.T) {
|
||||
errs := ValidateObjectMeta(
|
||||
&metav1.ObjectMeta{Name: "test", GenerateName: "foo-"},
|
||||
false,
|
||||
NameIsDNSSubdomain,
|
||||
field.NewPath("field"))
|
||||
if len(errs) != 0 {
|
||||
t.Fatalf("unexpected errors: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAnnotations(t *testing.T) {
|
||||
successCases := []map[string]string{
|
||||
{"simple": "bar"},
|
||||
{"now-with-dashes": "bar"},
|
||||
{"1-starts-with-num": "bar"},
|
||||
{"1234": "bar"},
|
||||
{"simple/simple": "bar"},
|
||||
{"now-with-dashes/simple": "bar"},
|
||||
{"now-with-dashes/now-with-dashes": "bar"},
|
||||
{"now.with.dots/simple": "bar"},
|
||||
{"now-with.dashes-and.dots/simple": "bar"},
|
||||
{"1-num.2-num/3-num": "bar"},
|
||||
{"1234/5678": "bar"},
|
||||
{"1.2.3.4/5678": "bar"},
|
||||
{"UpperCase123": "bar"},
|
||||
{"a": strings.Repeat("b", totalAnnotationSizeLimitB-1)},
|
||||
{
|
||||
"a": strings.Repeat("b", totalAnnotationSizeLimitB/2-1),
|
||||
"c": strings.Repeat("d", totalAnnotationSizeLimitB/2-1),
|
||||
},
|
||||
}
|
||||
for i := range successCases {
|
||||
errs := ValidateAnnotations(successCases[i], field.NewPath("field"))
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("case[%d] expected success, got %#v", i, errs)
|
||||
}
|
||||
}
|
||||
|
||||
nameErrorCases := []struct {
|
||||
annotations map[string]string
|
||||
expect string
|
||||
}{
|
||||
{map[string]string{"nospecialchars^=@": "bar"}, namePartErrMsg},
|
||||
{map[string]string{"cantendwithadash-": "bar"}, namePartErrMsg},
|
||||
{map[string]string{"only/one/slash": "bar"}, nameErrMsg},
|
||||
{map[string]string{strings.Repeat("a", 254): "bar"}, maxLengthErrMsg},
|
||||
}
|
||||
for i := range nameErrorCases {
|
||||
errs := ValidateAnnotations(nameErrorCases[i].annotations, field.NewPath("field"))
|
||||
if len(errs) != 1 {
|
||||
t.Errorf("case[%d]: expected failure", i)
|
||||
} else {
|
||||
if !strings.Contains(errs[0].Detail, nameErrorCases[i].expect) {
|
||||
t.Errorf("case[%d]: error details do not include %q: %q", i, nameErrorCases[i].expect, errs[0].Detail)
|
||||
}
|
||||
}
|
||||
}
|
||||
totalSizeErrorCases := []map[string]string{
|
||||
{"a": strings.Repeat("b", totalAnnotationSizeLimitB)},
|
||||
{
|
||||
"a": strings.Repeat("b", totalAnnotationSizeLimitB/2),
|
||||
"c": strings.Repeat("d", totalAnnotationSizeLimitB/2),
|
||||
},
|
||||
}
|
||||
for i := range totalSizeErrorCases {
|
||||
errs := ValidateAnnotations(totalSizeErrorCases[i], field.NewPath("field"))
|
||||
if len(errs) != 1 {
|
||||
t.Errorf("case[%d] expected failure", i)
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/k8s.io/apimachinery/pkg/api/validation/path/BUILD
generated
vendored
Normal file
33
vendor/k8s.io/apimachinery/pkg/api/validation/path/BUILD
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["name_test.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/validation/path",
|
||||
library = ":go_default_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["name.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/api/validation/path",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
68
vendor/k8s.io/apimachinery/pkg/api/validation/path/name.go
generated
vendored
Normal file
68
vendor/k8s.io/apimachinery/pkg/api/validation/path/name.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright 2015 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 path
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NameMayNotBe specifies strings that cannot be used as names specified as path segments (like the REST API or etcd store)
|
||||
var NameMayNotBe = []string{".", ".."}
|
||||
|
||||
// NameMayNotContain specifies substrings that cannot be used in names specified as path segments (like the REST API or etcd store)
|
||||
var NameMayNotContain = []string{"/", "%"}
|
||||
|
||||
// IsValidPathSegmentName validates the name can be safely encoded as a path segment
|
||||
func IsValidPathSegmentName(name string) []string {
|
||||
for _, illegalName := range NameMayNotBe {
|
||||
if name == illegalName {
|
||||
return []string{fmt.Sprintf(`may not be '%s'`, illegalName)}
|
||||
}
|
||||
}
|
||||
|
||||
var errors []string
|
||||
for _, illegalContent := range NameMayNotContain {
|
||||
if strings.Contains(name, illegalContent) {
|
||||
errors = append(errors, fmt.Sprintf(`may not contain '%s'`, illegalContent))
|
||||
}
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
// IsValidPathSegmentPrefix validates the name can be used as a prefix for a name which will be encoded as a path segment
|
||||
// It does not check for exact matches with disallowed names, since an arbitrary suffix might make the name valid
|
||||
func IsValidPathSegmentPrefix(name string) []string {
|
||||
var errors []string
|
||||
for _, illegalContent := range NameMayNotContain {
|
||||
if strings.Contains(name, illegalContent) {
|
||||
errors = append(errors, fmt.Sprintf(`may not contain '%s'`, illegalContent))
|
||||
}
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
// ValidatePathSegmentName validates the name can be safely encoded as a path segment
|
||||
func ValidatePathSegmentName(name string, prefix bool) []string {
|
||||
if prefix {
|
||||
return IsValidPathSegmentPrefix(name)
|
||||
} else {
|
||||
return IsValidPathSegmentName(name)
|
||||
}
|
||||
}
|
168
vendor/k8s.io/apimachinery/pkg/api/validation/path/name_test.go
generated
vendored
Normal file
168
vendor/k8s.io/apimachinery/pkg/api/validation/path/name_test.go
generated
vendored
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
Copyright 2015 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 path
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidatePathSegmentName(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
Name string
|
||||
Prefix bool
|
||||
ExpectedMsg string
|
||||
}{
|
||||
"empty": {
|
||||
Name: "",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
"empty,prefix": {
|
||||
Name: "",
|
||||
Prefix: true,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
|
||||
"valid": {
|
||||
Name: "foo.bar.baz",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
"valid,prefix": {
|
||||
Name: "foo.bar.baz",
|
||||
Prefix: true,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
|
||||
// Make sure mixed case, non DNS subdomain characters are tolerated
|
||||
"valid complex": {
|
||||
Name: "sha256:ABCDEF012345@ABCDEF012345",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
// Make sure non-ascii characters are tolerated
|
||||
"valid extended charset": {
|
||||
Name: "Iñtërnâtiônàlizætiøn",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
|
||||
"dot": {
|
||||
Name: ".",
|
||||
Prefix: false,
|
||||
ExpectedMsg: ".",
|
||||
},
|
||||
"dot leading": {
|
||||
Name: ".test",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
"dot,prefix": {
|
||||
Name: ".",
|
||||
Prefix: true,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
|
||||
"dot dot": {
|
||||
Name: "..",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "..",
|
||||
},
|
||||
"dot dot leading": {
|
||||
Name: "..test",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
"dot dot,prefix": {
|
||||
Name: "..",
|
||||
Prefix: true,
|
||||
ExpectedMsg: "",
|
||||
},
|
||||
|
||||
"slash": {
|
||||
Name: "foo/bar",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "/",
|
||||
},
|
||||
"slash,prefix": {
|
||||
Name: "foo/bar",
|
||||
Prefix: true,
|
||||
ExpectedMsg: "/",
|
||||
},
|
||||
|
||||
"percent": {
|
||||
Name: "foo%bar",
|
||||
Prefix: false,
|
||||
ExpectedMsg: "%",
|
||||
},
|
||||
"percent,prefix": {
|
||||
Name: "foo%bar",
|
||||
Prefix: true,
|
||||
ExpectedMsg: "%",
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range testcases {
|
||||
msgs := ValidatePathSegmentName(tc.Name, tc.Prefix)
|
||||
if len(tc.ExpectedMsg) == 0 && len(msgs) > 0 {
|
||||
t.Errorf("%s: expected no message, got %v", k, msgs)
|
||||
}
|
||||
if len(tc.ExpectedMsg) > 0 && len(msgs) == 0 {
|
||||
t.Errorf("%s: expected error message, got none", k)
|
||||
}
|
||||
if len(tc.ExpectedMsg) > 0 && !strings.Contains(msgs[0], tc.ExpectedMsg) {
|
||||
t.Errorf("%s: expected message containing %q, got %v", k, tc.ExpectedMsg, msgs[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateWithMultiErrors(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
Name string
|
||||
Prefix bool
|
||||
ExpectedMsg []string
|
||||
}{
|
||||
"slash,percent": {
|
||||
Name: "foo//bar%",
|
||||
Prefix: false,
|
||||
ExpectedMsg: []string{"may not contain '/'", "may not contain '%'"},
|
||||
},
|
||||
"slash,percent,prefix": {
|
||||
Name: "foo//bar%",
|
||||
Prefix: true,
|
||||
ExpectedMsg: []string{"may not contain '/'", "may not contain '%'"},
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range testcases {
|
||||
msgs := ValidatePathSegmentName(tc.Name, tc.Prefix)
|
||||
if len(tc.ExpectedMsg) == 0 && len(msgs) > 0 {
|
||||
t.Errorf("%s: expected no message, got %v", k, msgs)
|
||||
}
|
||||
if len(tc.ExpectedMsg) > 0 && len(msgs) == 0 {
|
||||
t.Errorf("%s: expected error message, got none", k)
|
||||
}
|
||||
if len(tc.ExpectedMsg) > 0 {
|
||||
for i := 0; i < len(tc.ExpectedMsg); i++ {
|
||||
if msgs[i] != tc.ExpectedMsg[i] {
|
||||
t.Errorf("%s: expected message containing %q, got %v", k, tc.ExpectedMsg[i], msgs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
46
vendor/k8s.io/apimachinery/pkg/apimachinery/BUILD
generated
vendored
Normal file
46
vendor/k8s.io/apimachinery/pkg/apimachinery/BUILD
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["types_test.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/apimachinery",
|
||||
library = ":go_default_library",
|
||||
deps = ["//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"types.go",
|
||||
],
|
||||
importpath = "k8s.io/apimachinery/pkg/apimachinery",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apimachinery/announced:all-srcs",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apimachinery/registered:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
46
vendor/k8s.io/apimachinery/pkg/apimachinery/announced/BUILD
generated
vendored
Normal file
46
vendor/k8s.io/apimachinery/pkg/apimachinery/announced/BUILD
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["announced_test.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/apimachinery/announced",
|
||||
library = ":go_default_library",
|
||||
deps = ["//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"announced.go",
|
||||
"group_factory.go",
|
||||
],
|
||||
importpath = "k8s.io/apimachinery/pkg/apimachinery/announced",
|
||||
deps = [
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
99
vendor/k8s.io/apimachinery/pkg/apimachinery/announced/announced.go
generated
vendored
Normal file
99
vendor/k8s.io/apimachinery/pkg/apimachinery/announced/announced.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright 2016 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 announced contains tools for announcing API group factories. This is
|
||||
// distinct from registration (in the 'registered' package) in that it's safe
|
||||
// to announce every possible group linked in, but only groups requested at
|
||||
// runtime should be registered. This package contains both a registry, and
|
||||
// factory code (which was formerly copy-pasta in every install package).
|
||||
package announced
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apimachinery/registered"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// APIGroupFactoryRegistry allows for groups and versions to announce themselves,
|
||||
// which simply makes them available and doesn't take other actions. Later,
|
||||
// users of the registry can select which groups and versions they'd actually
|
||||
// like to register with an APIRegistrationManager.
|
||||
//
|
||||
// (Right now APIRegistrationManager has separate 'registration' and 'enabled'
|
||||
// concepts-- APIGroupFactory is going to take over the former function;
|
||||
// they will overlap untill the refactoring is finished.)
|
||||
//
|
||||
// The key is the group name. After initialization, this should be treated as
|
||||
// read-only. It is implemented as a map from group name to group factory, and
|
||||
// it is safe to use this knowledge to manually pick out groups to register
|
||||
// (e.g., for testing).
|
||||
type APIGroupFactoryRegistry map[string]*GroupMetaFactory
|
||||
|
||||
func (gar APIGroupFactoryRegistry) group(groupName string) *GroupMetaFactory {
|
||||
gmf, ok := gar[groupName]
|
||||
if !ok {
|
||||
gmf = &GroupMetaFactory{VersionArgs: map[string]*GroupVersionFactoryArgs{}}
|
||||
gar[groupName] = gmf
|
||||
}
|
||||
return gmf
|
||||
}
|
||||
|
||||
// AnnounceGroupVersion adds the particular arguments for this group version to the group factory.
|
||||
func (gar APIGroupFactoryRegistry) AnnounceGroupVersion(gvf *GroupVersionFactoryArgs) error {
|
||||
gmf := gar.group(gvf.GroupName)
|
||||
if _, ok := gmf.VersionArgs[gvf.VersionName]; ok {
|
||||
return fmt.Errorf("version %q in group %q has already been announced", gvf.VersionName, gvf.GroupName)
|
||||
}
|
||||
gmf.VersionArgs[gvf.VersionName] = gvf
|
||||
return nil
|
||||
}
|
||||
|
||||
// AnnounceGroup adds the group-wide arguments to the group factory.
|
||||
func (gar APIGroupFactoryRegistry) AnnounceGroup(args *GroupMetaFactoryArgs) error {
|
||||
gmf := gar.group(args.GroupName)
|
||||
if gmf.GroupArgs != nil {
|
||||
return fmt.Errorf("group %q has already been announced", args.GroupName)
|
||||
}
|
||||
gmf.GroupArgs = args
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterAndEnableAll throws every factory at the specified API registration
|
||||
// manager, and lets it decide which to register. (If you want to do this a la
|
||||
// cart, you may look through gar itself-- it's just a map.)
|
||||
func (gar APIGroupFactoryRegistry) RegisterAndEnableAll(m *registered.APIRegistrationManager, scheme *runtime.Scheme) error {
|
||||
for groupName, gmf := range gar {
|
||||
if err := gmf.Register(m); err != nil {
|
||||
return fmt.Errorf("error registering %v: %v", groupName, err)
|
||||
}
|
||||
if err := gmf.Enable(m, scheme); err != nil {
|
||||
return fmt.Errorf("error enabling %v: %v", groupName, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AnnouncePreconstructedFactory announces a factory which you've manually assembled.
|
||||
// You may call this instead of calling AnnounceGroup and AnnounceGroupVersion.
|
||||
func (gar APIGroupFactoryRegistry) AnnouncePreconstructedFactory(gmf *GroupMetaFactory) error {
|
||||
name := gmf.GroupArgs.GroupName
|
||||
if _, exists := gar[name]; exists {
|
||||
return fmt.Errorf("the group %q has already been announced.", name)
|
||||
}
|
||||
gar[name] = gmf
|
||||
return nil
|
||||
}
|
64
vendor/k8s.io/apimachinery/pkg/apimachinery/announced/announced_test.go
generated
vendored
Normal file
64
vendor/k8s.io/apimachinery/pkg/apimachinery/announced/announced_test.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright 2016 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 announced
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
func TestFactoryRegistry(t *testing.T) {
|
||||
regA := make(APIGroupFactoryRegistry)
|
||||
regB := make(APIGroupFactoryRegistry)
|
||||
|
||||
if err := regA.AnnounceGroup(&GroupMetaFactoryArgs{
|
||||
GroupName: "foo",
|
||||
VersionPreferenceOrder: []string{"v2", "v1"},
|
||||
RootScopedKinds: sets.NewString("namespaces"),
|
||||
}); err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if err := regA.AnnounceGroupVersion(&GroupVersionFactoryArgs{
|
||||
GroupName: "foo",
|
||||
VersionName: "v1",
|
||||
}); err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
if err := regA.AnnounceGroupVersion(&GroupVersionFactoryArgs{
|
||||
GroupName: "foo",
|
||||
VersionName: "v2",
|
||||
}); err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if err := regB.AnnouncePreconstructedFactory(NewGroupMetaFactory(
|
||||
&GroupMetaFactoryArgs{
|
||||
GroupName: "foo",
|
||||
VersionPreferenceOrder: []string{"v2", "v1"},
|
||||
RootScopedKinds: sets.NewString("namespaces"),
|
||||
},
|
||||
VersionToSchemeFunc{"v1": nil, "v2": nil},
|
||||
)); err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(regA, regB) {
|
||||
t.Errorf("Expected both ways of registering to be equivalent, but they were not.\n\n%#v\n\n%#v\n", regA, regB)
|
||||
}
|
||||
}
|
255
vendor/k8s.io/apimachinery/pkg/apimachinery/announced/group_factory.go
generated
vendored
Normal file
255
vendor/k8s.io/apimachinery/pkg/apimachinery/announced/group_factory.go
generated
vendored
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
Copyright 2016 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 announced
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/apimachinery"
|
||||
"k8s.io/apimachinery/pkg/apimachinery/registered"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
type SchemeFunc func(*runtime.Scheme) error
|
||||
type VersionToSchemeFunc map[string]SchemeFunc
|
||||
|
||||
// GroupVersionFactoryArgs contains all the per-version parts of a GroupMetaFactory.
|
||||
type GroupVersionFactoryArgs struct {
|
||||
GroupName string
|
||||
VersionName string
|
||||
|
||||
AddToScheme SchemeFunc
|
||||
}
|
||||
|
||||
// GroupMetaFactoryArgs contains the group-level args of a GroupMetaFactory.
|
||||
type GroupMetaFactoryArgs struct {
|
||||
// GroupName is the name of the API-Group
|
||||
//
|
||||
// example: 'servicecatalog.k8s.io'
|
||||
GroupName string
|
||||
VersionPreferenceOrder []string
|
||||
// RootScopedKinds are resources that are not namespaced.
|
||||
RootScopedKinds sets.String // nil is allowed
|
||||
IgnoredKinds sets.String // nil is allowed
|
||||
|
||||
// May be nil if there are no internal objects.
|
||||
AddInternalObjectsToScheme SchemeFunc
|
||||
}
|
||||
|
||||
// NewGroupMetaFactory builds the args for you. This is for if you're
|
||||
// constructing a factory all at once and not using the registry.
|
||||
func NewGroupMetaFactory(groupArgs *GroupMetaFactoryArgs, versions VersionToSchemeFunc) *GroupMetaFactory {
|
||||
gmf := &GroupMetaFactory{
|
||||
GroupArgs: groupArgs,
|
||||
VersionArgs: map[string]*GroupVersionFactoryArgs{},
|
||||
}
|
||||
for v, f := range versions {
|
||||
gmf.VersionArgs[v] = &GroupVersionFactoryArgs{
|
||||
GroupName: groupArgs.GroupName,
|
||||
VersionName: v,
|
||||
AddToScheme: f,
|
||||
}
|
||||
}
|
||||
return gmf
|
||||
}
|
||||
|
||||
// Announce adds this Group factory to the global factory registry. It should
|
||||
// only be called if you constructed the GroupMetaFactory yourself via
|
||||
// NewGroupMetaFactory.
|
||||
// Note that this will panic on an error, since it's expected that you'll be
|
||||
// calling this at initialization time and any error is a result of a
|
||||
// programmer importing the wrong set of packages. If this assumption doesn't
|
||||
// work for you, just call DefaultGroupFactoryRegistry.AnnouncePreconstructedFactory
|
||||
// yourself.
|
||||
func (gmf *GroupMetaFactory) Announce(groupFactoryRegistry APIGroupFactoryRegistry) *GroupMetaFactory {
|
||||
if err := groupFactoryRegistry.AnnouncePreconstructedFactory(gmf); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return gmf
|
||||
}
|
||||
|
||||
// GroupMetaFactory has the logic for actually assembling and registering a group.
|
||||
//
|
||||
// There are two ways of obtaining one of these.
|
||||
// 1. You can announce your group and versions separately, and then let the
|
||||
// GroupFactoryRegistry assemble this object for you. (This allows group and
|
||||
// versions to be imported separately, without referencing each other, to
|
||||
// keep import trees small.)
|
||||
// 2. You can call NewGroupMetaFactory(), which is mostly a drop-in replacement
|
||||
// for the old, bad way of doing things. You can then call .Announce() to
|
||||
// announce your constructed factory to any code that would like to do
|
||||
// things the new, better way.
|
||||
//
|
||||
// Note that GroupMetaFactory actually does construct GroupMeta objects, but
|
||||
// currently it does so in a way that's very entangled with an
|
||||
// APIRegistrationManager. It's a TODO item to cleanly separate that interface.
|
||||
type GroupMetaFactory struct {
|
||||
GroupArgs *GroupMetaFactoryArgs
|
||||
// map of version name to version factory
|
||||
VersionArgs map[string]*GroupVersionFactoryArgs
|
||||
|
||||
// assembled by Register()
|
||||
prioritizedVersionList []schema.GroupVersion
|
||||
}
|
||||
|
||||
// Register constructs the finalized prioritized version list and sanity checks
|
||||
// the announced group & versions. Then it calls register.
|
||||
func (gmf *GroupMetaFactory) Register(m *registered.APIRegistrationManager) error {
|
||||
if gmf.GroupArgs == nil {
|
||||
return fmt.Errorf("partially announced groups are not allowed, only got versions: %#v", gmf.VersionArgs)
|
||||
}
|
||||
if len(gmf.VersionArgs) == 0 {
|
||||
return fmt.Errorf("group %v announced but no versions announced", gmf.GroupArgs.GroupName)
|
||||
}
|
||||
|
||||
pvSet := sets.NewString(gmf.GroupArgs.VersionPreferenceOrder...)
|
||||
if pvSet.Len() != len(gmf.GroupArgs.VersionPreferenceOrder) {
|
||||
return fmt.Errorf("preference order for group %v has duplicates: %v", gmf.GroupArgs.GroupName, gmf.GroupArgs.VersionPreferenceOrder)
|
||||
}
|
||||
prioritizedVersions := []schema.GroupVersion{}
|
||||
for _, v := range gmf.GroupArgs.VersionPreferenceOrder {
|
||||
prioritizedVersions = append(
|
||||
prioritizedVersions,
|
||||
schema.GroupVersion{
|
||||
Group: gmf.GroupArgs.GroupName,
|
||||
Version: v,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Go through versions that weren't explicitly prioritized.
|
||||
unprioritizedVersions := []schema.GroupVersion{}
|
||||
for _, v := range gmf.VersionArgs {
|
||||
if v.GroupName != gmf.GroupArgs.GroupName {
|
||||
return fmt.Errorf("found %v/%v in group %v?", v.GroupName, v.VersionName, gmf.GroupArgs.GroupName)
|
||||
}
|
||||
if pvSet.Has(v.VersionName) {
|
||||
pvSet.Delete(v.VersionName)
|
||||
continue
|
||||
}
|
||||
unprioritizedVersions = append(unprioritizedVersions, schema.GroupVersion{Group: v.GroupName, Version: v.VersionName})
|
||||
}
|
||||
if len(unprioritizedVersions) > 1 {
|
||||
glog.Warningf("group %v has multiple unprioritized versions: %#v. They will have an arbitrary preference order!", gmf.GroupArgs.GroupName, unprioritizedVersions)
|
||||
}
|
||||
if pvSet.Len() != 0 {
|
||||
return fmt.Errorf("group %v has versions in the priority list that were never announced: %s", gmf.GroupArgs.GroupName, pvSet)
|
||||
}
|
||||
prioritizedVersions = append(prioritizedVersions, unprioritizedVersions...)
|
||||
m.RegisterVersions(prioritizedVersions)
|
||||
gmf.prioritizedVersionList = prioritizedVersions
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gmf *GroupMetaFactory) newRESTMapper(scheme *runtime.Scheme, externalVersions []schema.GroupVersion, groupMeta *apimachinery.GroupMeta) meta.RESTMapper {
|
||||
// the list of kinds that are scoped at the root of the api hierarchy
|
||||
// if a kind is not enumerated here, it is assumed to have a namespace scope
|
||||
rootScoped := sets.NewString()
|
||||
if gmf.GroupArgs.RootScopedKinds != nil {
|
||||
rootScoped = gmf.GroupArgs.RootScopedKinds
|
||||
}
|
||||
ignoredKinds := sets.NewString()
|
||||
if gmf.GroupArgs.IgnoredKinds != nil {
|
||||
ignoredKinds = gmf.GroupArgs.IgnoredKinds
|
||||
}
|
||||
|
||||
mapper := meta.NewDefaultRESTMapper(externalVersions, groupMeta.InterfacesFor)
|
||||
for _, gv := range externalVersions {
|
||||
for kind := range scheme.KnownTypes(gv) {
|
||||
if ignoredKinds.Has(kind) {
|
||||
continue
|
||||
}
|
||||
scope := meta.RESTScopeNamespace
|
||||
if rootScoped.Has(kind) {
|
||||
scope = meta.RESTScopeRoot
|
||||
}
|
||||
mapper.Add(gv.WithKind(kind), scope)
|
||||
}
|
||||
}
|
||||
|
||||
return mapper
|
||||
}
|
||||
|
||||
// Enable enables group versions that are allowed, adds methods to the scheme, etc.
|
||||
func (gmf *GroupMetaFactory) Enable(m *registered.APIRegistrationManager, scheme *runtime.Scheme) error {
|
||||
externalVersions := []schema.GroupVersion{}
|
||||
for _, v := range gmf.prioritizedVersionList {
|
||||
if !m.IsAllowedVersion(v) {
|
||||
continue
|
||||
}
|
||||
externalVersions = append(externalVersions, v)
|
||||
if err := m.EnableVersions(v); err != nil {
|
||||
return err
|
||||
}
|
||||
gmf.VersionArgs[v.Version].AddToScheme(scheme)
|
||||
}
|
||||
if len(externalVersions) == 0 {
|
||||
glog.V(4).Infof("No version is registered for group %v", gmf.GroupArgs.GroupName)
|
||||
return nil
|
||||
}
|
||||
|
||||
if gmf.GroupArgs.AddInternalObjectsToScheme != nil {
|
||||
gmf.GroupArgs.AddInternalObjectsToScheme(scheme)
|
||||
}
|
||||
|
||||
preferredExternalVersion := externalVersions[0]
|
||||
accessor := meta.NewAccessor()
|
||||
|
||||
groupMeta := &apimachinery.GroupMeta{
|
||||
GroupVersion: preferredExternalVersion,
|
||||
GroupVersions: externalVersions,
|
||||
SelfLinker: runtime.SelfLinker(accessor),
|
||||
}
|
||||
for _, v := range externalVersions {
|
||||
gvf := gmf.VersionArgs[v.Version]
|
||||
if err := groupMeta.AddVersionInterfaces(
|
||||
schema.GroupVersion{Group: gvf.GroupName, Version: gvf.VersionName},
|
||||
&meta.VersionInterfaces{
|
||||
ObjectConvertor: scheme,
|
||||
MetadataAccessor: accessor,
|
||||
},
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
groupMeta.InterfacesFor = groupMeta.DefaultInterfacesFor
|
||||
groupMeta.RESTMapper = gmf.newRESTMapper(scheme, externalVersions, groupMeta)
|
||||
|
||||
if err := m.RegisterGroup(*groupMeta); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterAndEnable is provided only to allow this code to get added in multiple steps.
|
||||
// It's really bad that this is called in init() methods, but supporting this
|
||||
// temporarily lets us do the change incrementally.
|
||||
func (gmf *GroupMetaFactory) RegisterAndEnable(registry *registered.APIRegistrationManager, scheme *runtime.Scheme) error {
|
||||
if err := gmf.Register(registry); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gmf.Enable(registry, scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
20
vendor/k8s.io/apimachinery/pkg/apimachinery/doc.go
generated
vendored
Normal file
20
vendor/k8s.io/apimachinery/pkg/apimachinery/doc.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 2014 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 apimachinery contains the generic API machinery code that
|
||||
// is common to both server and clients.
|
||||
// This package should never import specific API objects.
|
||||
package apimachinery // import "k8s.io/apimachinery/pkg/apimachinery"
|
44
vendor/k8s.io/apimachinery/pkg/apimachinery/registered/BUILD
generated
vendored
Normal file
44
vendor/k8s.io/apimachinery/pkg/apimachinery/registered/BUILD
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["registered_test.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/apimachinery/registered",
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["registered.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/apimachinery/registered",
|
||||
deps = [
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
336
vendor/k8s.io/apimachinery/pkg/apimachinery/registered/registered.go
generated
vendored
Normal file
336
vendor/k8s.io/apimachinery/pkg/apimachinery/registered/registered.go
generated
vendored
Normal file
@ -0,0 +1,336 @@
|
||||
/*
|
||||
Copyright 2015 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 to keep track of API Versions that can be registered and are enabled in a Scheme.
|
||||
package registered
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/apimachinery"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
// APIRegistrationManager provides the concept of what API groups are enabled.
|
||||
//
|
||||
// TODO: currently, it also provides a "registered" concept. But it's wrong to
|
||||
// have both concepts in the same object. Therefore the "announced" package is
|
||||
// going to take over the registered concept. After all the install packages
|
||||
// are switched to using the announce package instead of this package, then we
|
||||
// can combine the registered/enabled concepts in this object. Simplifying this
|
||||
// isn't easy right now because there are so many callers of this package.
|
||||
type APIRegistrationManager struct {
|
||||
// registeredGroupVersions stores all API group versions for which RegisterGroup is called.
|
||||
registeredVersions map[schema.GroupVersion]struct{}
|
||||
|
||||
// enabledVersions represents all enabled API versions. It should be a
|
||||
// subset of registeredVersions. Please call EnableVersions() to add
|
||||
// enabled versions.
|
||||
enabledVersions map[schema.GroupVersion]struct{}
|
||||
|
||||
// map of group meta for all groups.
|
||||
groupMetaMap map[string]*apimachinery.GroupMeta
|
||||
|
||||
// envRequestedVersions represents the versions requested via the
|
||||
// KUBE_API_VERSIONS environment variable. The install package of each group
|
||||
// checks this list before add their versions to the latest package and
|
||||
// Scheme. This list is small and order matters, so represent as a slice
|
||||
envRequestedVersions []schema.GroupVersion
|
||||
}
|
||||
|
||||
// NewAPIRegistrationManager constructs a new manager. The argument ought to be
|
||||
// the value of the KUBE_API_VERSIONS env var, or a value of this which you
|
||||
// wish to test.
|
||||
func NewAPIRegistrationManager(kubeAPIVersions string) (*APIRegistrationManager, error) {
|
||||
m := &APIRegistrationManager{
|
||||
registeredVersions: map[schema.GroupVersion]struct{}{},
|
||||
enabledVersions: map[schema.GroupVersion]struct{}{},
|
||||
groupMetaMap: map[string]*apimachinery.GroupMeta{},
|
||||
envRequestedVersions: []schema.GroupVersion{},
|
||||
}
|
||||
|
||||
if len(kubeAPIVersions) != 0 {
|
||||
for _, version := range strings.Split(kubeAPIVersions, ",") {
|
||||
gv, err := schema.ParseGroupVersion(version)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid api version: %s in KUBE_API_VERSIONS: %s.",
|
||||
version, kubeAPIVersions)
|
||||
}
|
||||
m.envRequestedVersions = append(m.envRequestedVersions, gv)
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func NewOrDie(kubeAPIVersions string) *APIRegistrationManager {
|
||||
m, err := NewAPIRegistrationManager(kubeAPIVersions)
|
||||
if err != nil {
|
||||
glog.Fatalf("Could not construct version manager: %v (KUBE_API_VERSIONS=%q)", err, kubeAPIVersions)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// RegisterVersions adds the given group versions to the list of registered group versions.
|
||||
func (m *APIRegistrationManager) RegisterVersions(availableVersions []schema.GroupVersion) {
|
||||
for _, v := range availableVersions {
|
||||
m.registeredVersions[v] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterGroup adds the given group to the list of registered groups.
|
||||
func (m *APIRegistrationManager) RegisterGroup(groupMeta apimachinery.GroupMeta) error {
|
||||
groupName := groupMeta.GroupVersion.Group
|
||||
if _, found := m.groupMetaMap[groupName]; found {
|
||||
return fmt.Errorf("group %q is already registered in groupsMap: %v", groupName, m.groupMetaMap)
|
||||
}
|
||||
m.groupMetaMap[groupName] = &groupMeta
|
||||
return nil
|
||||
}
|
||||
|
||||
// EnableVersions adds the versions for the given group to the list of enabled versions.
|
||||
// Note that the caller should call RegisterGroup before calling this method.
|
||||
// The caller of this function is responsible to add the versions to scheme and RESTMapper.
|
||||
func (m *APIRegistrationManager) EnableVersions(versions ...schema.GroupVersion) error {
|
||||
var unregisteredVersions []schema.GroupVersion
|
||||
for _, v := range versions {
|
||||
if _, found := m.registeredVersions[v]; !found {
|
||||
unregisteredVersions = append(unregisteredVersions, v)
|
||||
}
|
||||
m.enabledVersions[v] = struct{}{}
|
||||
}
|
||||
if len(unregisteredVersions) != 0 {
|
||||
return fmt.Errorf("Please register versions before enabling them: %v", unregisteredVersions)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsAllowedVersion returns if the version is allowed by the KUBE_API_VERSIONS
|
||||
// environment variable. If the environment variable is empty, then it always
|
||||
// returns true.
|
||||
func (m *APIRegistrationManager) IsAllowedVersion(v schema.GroupVersion) bool {
|
||||
if len(m.envRequestedVersions) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, envGV := range m.envRequestedVersions {
|
||||
if v == envGV {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsEnabledVersion returns if a version is enabled.
|
||||
func (m *APIRegistrationManager) IsEnabledVersion(v schema.GroupVersion) bool {
|
||||
_, found := m.enabledVersions[v]
|
||||
return found
|
||||
}
|
||||
|
||||
// EnabledVersions returns all enabled versions. Groups are randomly ordered, but versions within groups
|
||||
// are priority order from best to worst
|
||||
func (m *APIRegistrationManager) EnabledVersions() []schema.GroupVersion {
|
||||
ret := []schema.GroupVersion{}
|
||||
for _, groupMeta := range m.groupMetaMap {
|
||||
for _, version := range groupMeta.GroupVersions {
|
||||
if m.IsEnabledVersion(version) {
|
||||
ret = append(ret, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// EnabledVersionsForGroup returns all enabled versions for a group in order of best to worst
|
||||
func (m *APIRegistrationManager) EnabledVersionsForGroup(group string) []schema.GroupVersion {
|
||||
groupMeta, ok := m.groupMetaMap[group]
|
||||
if !ok {
|
||||
return []schema.GroupVersion{}
|
||||
}
|
||||
|
||||
ret := []schema.GroupVersion{}
|
||||
for _, version := range groupMeta.GroupVersions {
|
||||
if m.IsEnabledVersion(version) {
|
||||
ret = append(ret, version)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Group returns the metadata of a group if the group is registered, otherwise
|
||||
// an error is returned.
|
||||
func (m *APIRegistrationManager) Group(group string) (*apimachinery.GroupMeta, error) {
|
||||
groupMeta, found := m.groupMetaMap[group]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("group %v has not been registered", group)
|
||||
}
|
||||
groupMetaCopy := *groupMeta
|
||||
return &groupMetaCopy, nil
|
||||
}
|
||||
|
||||
// IsRegistered takes a string and determines if it's one of the registered groups
|
||||
func (m *APIRegistrationManager) IsRegistered(group string) bool {
|
||||
_, found := m.groupMetaMap[group]
|
||||
return found
|
||||
}
|
||||
|
||||
// IsRegisteredVersion returns if a version is registered.
|
||||
func (m *APIRegistrationManager) IsRegisteredVersion(v schema.GroupVersion) bool {
|
||||
_, found := m.registeredVersions[v]
|
||||
return found
|
||||
}
|
||||
|
||||
// RegisteredGroupVersions returns all registered group versions.
|
||||
func (m *APIRegistrationManager) RegisteredGroupVersions() []schema.GroupVersion {
|
||||
ret := []schema.GroupVersion{}
|
||||
for groupVersion := range m.registeredVersions {
|
||||
ret = append(ret, groupVersion)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// InterfacesFor is a union meta.VersionInterfacesFunc func for all registered types
|
||||
func (m *APIRegistrationManager) InterfacesFor(version schema.GroupVersion) (*meta.VersionInterfaces, error) {
|
||||
groupMeta, err := m.Group(version.Group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return groupMeta.InterfacesFor(version)
|
||||
}
|
||||
|
||||
// TODO: This is an expedient function, because we don't check if a Group is
|
||||
// supported throughout the code base. We will abandon this function and
|
||||
// checking the error returned by the Group() function.
|
||||
func (m *APIRegistrationManager) GroupOrDie(group string) *apimachinery.GroupMeta {
|
||||
groupMeta, found := m.groupMetaMap[group]
|
||||
if !found {
|
||||
if group == "" {
|
||||
panic("The legacy v1 API is not registered.")
|
||||
} else {
|
||||
panic(fmt.Sprintf("Group %s is not registered.", group))
|
||||
}
|
||||
}
|
||||
groupMetaCopy := *groupMeta
|
||||
return &groupMetaCopy
|
||||
}
|
||||
|
||||
// RESTMapper returns a union RESTMapper of all known types with priorities chosen in the following order:
|
||||
// 1. if KUBE_API_VERSIONS is specified, then KUBE_API_VERSIONS in order, OR
|
||||
// 1. legacy kube group preferred version, extensions preferred version, metrics perferred version, legacy
|
||||
// kube any version, extensions any version, metrics any version, all other groups alphabetical preferred version,
|
||||
// all other groups alphabetical.
|
||||
func (m *APIRegistrationManager) RESTMapper(versionPatterns ...schema.GroupVersion) meta.RESTMapper {
|
||||
unionMapper := meta.MultiRESTMapper{}
|
||||
unionedGroups := sets.NewString()
|
||||
for enabledVersion := range m.enabledVersions {
|
||||
if !unionedGroups.Has(enabledVersion.Group) {
|
||||
unionedGroups.Insert(enabledVersion.Group)
|
||||
groupMeta := m.groupMetaMap[enabledVersion.Group]
|
||||
unionMapper = append(unionMapper, groupMeta.RESTMapper)
|
||||
}
|
||||
}
|
||||
|
||||
if len(versionPatterns) != 0 {
|
||||
resourcePriority := []schema.GroupVersionResource{}
|
||||
kindPriority := []schema.GroupVersionKind{}
|
||||
for _, versionPriority := range versionPatterns {
|
||||
resourcePriority = append(resourcePriority, versionPriority.WithResource(meta.AnyResource))
|
||||
kindPriority = append(kindPriority, versionPriority.WithKind(meta.AnyKind))
|
||||
}
|
||||
|
||||
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
|
||||
}
|
||||
|
||||
if len(m.envRequestedVersions) != 0 {
|
||||
resourcePriority := []schema.GroupVersionResource{}
|
||||
kindPriority := []schema.GroupVersionKind{}
|
||||
|
||||
for _, versionPriority := range m.envRequestedVersions {
|
||||
resourcePriority = append(resourcePriority, versionPriority.WithResource(meta.AnyResource))
|
||||
kindPriority = append(kindPriority, versionPriority.WithKind(meta.AnyKind))
|
||||
}
|
||||
|
||||
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
|
||||
}
|
||||
|
||||
prioritizedGroups := []string{"", "extensions", "metrics"}
|
||||
resourcePriority, kindPriority := m.prioritiesForGroups(prioritizedGroups...)
|
||||
|
||||
prioritizedGroupsSet := sets.NewString(prioritizedGroups...)
|
||||
remainingGroups := sets.String{}
|
||||
for enabledVersion := range m.enabledVersions {
|
||||
if !prioritizedGroupsSet.Has(enabledVersion.Group) {
|
||||
remainingGroups.Insert(enabledVersion.Group)
|
||||
}
|
||||
}
|
||||
|
||||
remainingResourcePriority, remainingKindPriority := m.prioritiesForGroups(remainingGroups.List()...)
|
||||
resourcePriority = append(resourcePriority, remainingResourcePriority...)
|
||||
kindPriority = append(kindPriority, remainingKindPriority...)
|
||||
|
||||
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
|
||||
}
|
||||
|
||||
// prioritiesForGroups returns the resource and kind priorities for a PriorityRESTMapper, preferring the preferred version of each group first,
|
||||
// then any non-preferred version of the group second.
|
||||
func (m *APIRegistrationManager) prioritiesForGroups(groups ...string) ([]schema.GroupVersionResource, []schema.GroupVersionKind) {
|
||||
resourcePriority := []schema.GroupVersionResource{}
|
||||
kindPriority := []schema.GroupVersionKind{}
|
||||
|
||||
for _, group := range groups {
|
||||
availableVersions := m.EnabledVersionsForGroup(group)
|
||||
if len(availableVersions) > 0 {
|
||||
resourcePriority = append(resourcePriority, availableVersions[0].WithResource(meta.AnyResource))
|
||||
kindPriority = append(kindPriority, availableVersions[0].WithKind(meta.AnyKind))
|
||||
}
|
||||
}
|
||||
for _, group := range groups {
|
||||
resourcePriority = append(resourcePriority, schema.GroupVersionResource{Group: group, Version: meta.AnyVersion, Resource: meta.AnyResource})
|
||||
kindPriority = append(kindPriority, schema.GroupVersionKind{Group: group, Version: meta.AnyVersion, Kind: meta.AnyKind})
|
||||
}
|
||||
|
||||
return resourcePriority, kindPriority
|
||||
}
|
||||
|
||||
// AllPreferredGroupVersions returns the preferred versions of all registered
|
||||
// groups in the form of "group1/version1,group2/version2,..."
|
||||
func (m *APIRegistrationManager) AllPreferredGroupVersions() string {
|
||||
if len(m.groupMetaMap) == 0 {
|
||||
return ""
|
||||
}
|
||||
var defaults []string
|
||||
for _, groupMeta := range m.groupMetaMap {
|
||||
defaults = append(defaults, groupMeta.GroupVersion.String())
|
||||
}
|
||||
sort.Strings(defaults)
|
||||
return strings.Join(defaults, ",")
|
||||
}
|
||||
|
||||
// ValidateEnvRequestedVersions returns a list of versions that are requested in
|
||||
// the KUBE_API_VERSIONS environment variable, but not enabled.
|
||||
func (m *APIRegistrationManager) ValidateEnvRequestedVersions() []schema.GroupVersion {
|
||||
var missingVersions []schema.GroupVersion
|
||||
for _, v := range m.envRequestedVersions {
|
||||
if _, found := m.enabledVersions[v]; !found {
|
||||
missingVersions = append(missingVersions, v)
|
||||
}
|
||||
}
|
||||
return missingVersions
|
||||
}
|
71
vendor/k8s.io/apimachinery/pkg/apimachinery/registered/registered_test.go
generated
vendored
Normal file
71
vendor/k8s.io/apimachinery/pkg/apimachinery/registered/registered_test.go
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright 2015 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 registered
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apimachinery"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func TestAllPreferredGroupVersions(t *testing.T) {
|
||||
testCases := []struct {
|
||||
groupMetas []apimachinery.GroupMeta
|
||||
expect string
|
||||
}{
|
||||
{
|
||||
groupMetas: []apimachinery.GroupMeta{
|
||||
{
|
||||
GroupVersion: schema.GroupVersion{Group: "group1", Version: "v1"},
|
||||
},
|
||||
{
|
||||
GroupVersion: schema.GroupVersion{Group: "group2", Version: "v2"},
|
||||
},
|
||||
{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
},
|
||||
},
|
||||
expect: "group1/v1,group2/v2,v1",
|
||||
},
|
||||
{
|
||||
groupMetas: []apimachinery.GroupMeta{
|
||||
{
|
||||
GroupVersion: schema.GroupVersion{Group: "", Version: "v1"},
|
||||
},
|
||||
},
|
||||
expect: "v1",
|
||||
},
|
||||
{
|
||||
groupMetas: []apimachinery.GroupMeta{},
|
||||
expect: "",
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
m, err := NewAPIRegistrationManager("")
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected failure to make a manager: %v", err)
|
||||
}
|
||||
for _, groupMeta := range testCase.groupMetas {
|
||||
m.RegisterGroup(groupMeta)
|
||||
}
|
||||
output := m.AllPreferredGroupVersions()
|
||||
if testCase.expect != output {
|
||||
t.Errorf("Error. expect: %s, got: %s", testCase.expect, output)
|
||||
}
|
||||
}
|
||||
}
|
87
vendor/k8s.io/apimachinery/pkg/apimachinery/types.go
generated
vendored
Normal file
87
vendor/k8s.io/apimachinery/pkg/apimachinery/types.go
generated
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
Copyright 2016 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 apimachinery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// GroupMeta stores the metadata of a group.
|
||||
type GroupMeta struct {
|
||||
// GroupVersion represents the preferred version of the group.
|
||||
GroupVersion schema.GroupVersion
|
||||
|
||||
// GroupVersions is Group + all versions in that group.
|
||||
GroupVersions []schema.GroupVersion
|
||||
|
||||
// SelfLinker can set or get the SelfLink field of all API types.
|
||||
// TODO: when versioning changes, make this part of each API definition.
|
||||
// TODO(lavalamp): Combine SelfLinker & ResourceVersioner interfaces, force all uses
|
||||
// to go through the InterfacesFor method below.
|
||||
SelfLinker runtime.SelfLinker
|
||||
|
||||
// RESTMapper provides the default mapping between REST paths and the objects declared in a Scheme and all known
|
||||
// versions.
|
||||
RESTMapper meta.RESTMapper
|
||||
|
||||
// InterfacesFor returns the default Codec and ResourceVersioner for a given version
|
||||
// string, or an error if the version is not known.
|
||||
// TODO: make this stop being a func pointer and always use the default
|
||||
// function provided below once every place that populates this field has been changed.
|
||||
InterfacesFor func(version schema.GroupVersion) (*meta.VersionInterfaces, error)
|
||||
|
||||
// InterfacesByVersion stores the per-version interfaces.
|
||||
InterfacesByVersion map[schema.GroupVersion]*meta.VersionInterfaces
|
||||
}
|
||||
|
||||
// DefaultInterfacesFor returns the default Codec and ResourceVersioner for a given version
|
||||
// string, or an error if the version is not known.
|
||||
// TODO: Remove the "Default" prefix.
|
||||
func (gm *GroupMeta) DefaultInterfacesFor(version schema.GroupVersion) (*meta.VersionInterfaces, error) {
|
||||
if v, ok := gm.InterfacesByVersion[version]; ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported storage version: %s (valid: %v)", version, gm.GroupVersions)
|
||||
}
|
||||
|
||||
// AddVersionInterfaces adds the given version to the group. Only call during
|
||||
// init, after that GroupMeta objects should be immutable. Not thread safe.
|
||||
// (If you use this, be sure to set .InterfacesFor = .DefaultInterfacesFor)
|
||||
// TODO: remove the "Interfaces" suffix and make this also maintain the
|
||||
// .GroupVersions member.
|
||||
func (gm *GroupMeta) AddVersionInterfaces(version schema.GroupVersion, interfaces *meta.VersionInterfaces) error {
|
||||
if e, a := gm.GroupVersion.Group, version.Group; a != e {
|
||||
return fmt.Errorf("got a version in group %v, but am in group %v", a, e)
|
||||
}
|
||||
if gm.InterfacesByVersion == nil {
|
||||
gm.InterfacesByVersion = make(map[schema.GroupVersion]*meta.VersionInterfaces)
|
||||
}
|
||||
gm.InterfacesByVersion[version] = interfaces
|
||||
|
||||
// TODO: refactor to make the below error not possible, this function
|
||||
// should *set* GroupVersions rather than depend on it.
|
||||
for _, v := range gm.GroupVersions {
|
||||
if v == version {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("added a version interface without the corresponding version %v being in the list %#v", version, gm.GroupVersions)
|
||||
}
|
43
vendor/k8s.io/apimachinery/pkg/apimachinery/types_test.go
generated
vendored
Normal file
43
vendor/k8s.io/apimachinery/pkg/apimachinery/types_test.go
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright 2016 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 apimachinery
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
gm := GroupMeta{
|
||||
GroupVersion: schema.GroupVersion{
|
||||
Group: "test",
|
||||
Version: "v1",
|
||||
},
|
||||
GroupVersions: []schema.GroupVersion{{Group: "test", Version: "v1"}},
|
||||
}
|
||||
|
||||
gm.AddVersionInterfaces(schema.GroupVersion{Group: "test", Version: "v1"}, nil)
|
||||
if e, a := 1, len(gm.InterfacesByVersion); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
|
||||
// GroupVersions is unchanged
|
||||
if e, a := 1, len(gm.GroupVersions); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
36
vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer/BUILD
generated
vendored
Normal file
36
vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer/BUILD
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["fuzzer.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/apis/meta/fuzzer",
|
||||
deps = [
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/testing:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
298
vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer/fuzzer.go
generated
vendored
Normal file
298
vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer/fuzzer.go
generated
vendored
Normal file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
Copyright 2017 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 fuzzer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
apitesting "k8s.io/apimachinery/pkg/api/testing"
|
||||
"k8s.io/apimachinery/pkg/api/testing/fuzzer"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1alpha1 "k8s.io/apimachinery/pkg/apis/meta/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func genericFuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
return []interface{}{
|
||||
func(q *resource.Quantity, c fuzz.Continue) {
|
||||
*q = *resource.NewQuantity(c.Int63n(1000), resource.DecimalExponent)
|
||||
},
|
||||
func(j *int, c fuzz.Continue) {
|
||||
*j = int(c.Int31())
|
||||
},
|
||||
func(j **int, c fuzz.Continue) {
|
||||
if c.RandBool() {
|
||||
i := int(c.Int31())
|
||||
*j = &i
|
||||
} else {
|
||||
*j = nil
|
||||
}
|
||||
},
|
||||
func(j *runtime.TypeMeta, c fuzz.Continue) {
|
||||
// We have to customize the randomization of TypeMetas because their
|
||||
// APIVersion and Kind must remain blank in memory.
|
||||
j.APIVersion = ""
|
||||
j.Kind = ""
|
||||
},
|
||||
func(j *runtime.Object, c fuzz.Continue) {
|
||||
// TODO: uncomment when round trip starts from a versioned object
|
||||
if true { //c.RandBool() {
|
||||
*j = &runtime.Unknown{
|
||||
// We do not set TypeMeta here because it is not carried through a round trip
|
||||
Raw: []byte(`{"apiVersion":"unknown.group/unknown","kind":"Something","someKey":"someValue"}`),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
}
|
||||
} else {
|
||||
types := []runtime.Object{&metav1.Status{}, &metav1.APIGroup{}}
|
||||
t := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(t)
|
||||
*j = t
|
||||
}
|
||||
},
|
||||
func(r *runtime.RawExtension, c fuzz.Continue) {
|
||||
// Pick an arbitrary type and fuzz it
|
||||
types := []runtime.Object{&metav1.Status{}, &metav1.APIGroup{}}
|
||||
obj := types[c.Rand.Intn(len(types))]
|
||||
c.Fuzz(obj)
|
||||
|
||||
// Find a codec for converting the object to raw bytes. This is necessary for the
|
||||
// api version and kind to be correctly set be serialization.
|
||||
var codec = apitesting.TestCodec(codecs, metav1.SchemeGroupVersion)
|
||||
|
||||
// Convert the object to raw bytes
|
||||
bytes, err := runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Failed to encode object: %v", err))
|
||||
}
|
||||
|
||||
// strip trailing newlines which do not survive roundtrips
|
||||
for len(bytes) >= 1 && bytes[len(bytes)-1] == 10 {
|
||||
bytes = bytes[:len(bytes)-1]
|
||||
}
|
||||
|
||||
// Set the bytes field on the RawExtension
|
||||
r.Raw = bytes
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// taken from gofuzz internals for RandString
|
||||
type charRange struct {
|
||||
first, last rune
|
||||
}
|
||||
|
||||
func (c *charRange) choose(r *rand.Rand) rune {
|
||||
count := int64(c.last - c.first + 1)
|
||||
ch := c.first + rune(r.Int63n(count))
|
||||
|
||||
return ch
|
||||
}
|
||||
|
||||
// randomLabelPart produces a valid random label value or name-part
|
||||
// of a label key.
|
||||
func randomLabelPart(c fuzz.Continue, canBeEmpty bool) string {
|
||||
validStartEnd := []charRange{{'0', '9'}, {'a', 'z'}, {'A', 'Z'}}
|
||||
validMiddle := []charRange{{'0', '9'}, {'a', 'z'}, {'A', 'Z'},
|
||||
{'.', '.'}, {'-', '-'}, {'_', '_'}}
|
||||
|
||||
partLen := c.Rand.Intn(64) // len is [0, 63]
|
||||
if !canBeEmpty {
|
||||
partLen = c.Rand.Intn(63) + 1 // len is [1, 63]
|
||||
}
|
||||
|
||||
runes := make([]rune, partLen)
|
||||
if partLen == 0 {
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
runes[0] = validStartEnd[c.Rand.Intn(len(validStartEnd))].choose(c.Rand)
|
||||
for i := range runes[1:] {
|
||||
runes[i+1] = validMiddle[c.Rand.Intn(len(validMiddle))].choose(c.Rand)
|
||||
}
|
||||
runes[len(runes)-1] = validStartEnd[c.Rand.Intn(len(validStartEnd))].choose(c.Rand)
|
||||
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
func randomDNSLabel(c fuzz.Continue) string {
|
||||
validStartEnd := []charRange{{'0', '9'}, {'a', 'z'}}
|
||||
validMiddle := []charRange{{'0', '9'}, {'a', 'z'}, {'-', '-'}}
|
||||
|
||||
partLen := c.Rand.Intn(63) + 1 // len is [1, 63]
|
||||
runes := make([]rune, partLen)
|
||||
|
||||
runes[0] = validStartEnd[c.Rand.Intn(len(validStartEnd))].choose(c.Rand)
|
||||
for i := range runes[1:] {
|
||||
runes[i+1] = validMiddle[c.Rand.Intn(len(validMiddle))].choose(c.Rand)
|
||||
}
|
||||
runes[len(runes)-1] = validStartEnd[c.Rand.Intn(len(validStartEnd))].choose(c.Rand)
|
||||
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
func randomLabelKey(c fuzz.Continue) string {
|
||||
namePart := randomLabelPart(c, false)
|
||||
prefixPart := ""
|
||||
|
||||
usePrefix := c.RandBool()
|
||||
if usePrefix {
|
||||
// we can fit, with dots, at most 3 labels in the 253 allotted characters
|
||||
prefixPartsLen := c.Rand.Intn(2) + 1
|
||||
prefixParts := make([]string, prefixPartsLen)
|
||||
for i := range prefixParts {
|
||||
prefixParts[i] = randomDNSLabel(c)
|
||||
}
|
||||
prefixPart = strings.Join(prefixParts, ".") + "/"
|
||||
}
|
||||
|
||||
return prefixPart + namePart
|
||||
}
|
||||
|
||||
func v1FuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
|
||||
return []interface{}{
|
||||
func(j *metav1.TypeMeta, c fuzz.Continue) {
|
||||
// We have to customize the randomization of TypeMetas because their
|
||||
// APIVersion and Kind must remain blank in memory.
|
||||
j.APIVersion = ""
|
||||
j.Kind = ""
|
||||
},
|
||||
func(j *metav1.ObjectMeta, c fuzz.Continue) {
|
||||
j.Name = c.RandString()
|
||||
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
|
||||
j.SelfLink = c.RandString()
|
||||
j.UID = types.UID(c.RandString())
|
||||
j.GenerateName = c.RandString()
|
||||
|
||||
var sec, nsec int64
|
||||
c.Fuzz(&sec)
|
||||
c.Fuzz(&nsec)
|
||||
j.CreationTimestamp = metav1.Unix(sec, nsec).Rfc3339Copy()
|
||||
},
|
||||
func(j *metav1.ListMeta, c fuzz.Continue) {
|
||||
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
|
||||
j.SelfLink = c.RandString()
|
||||
},
|
||||
func(j *metav1.LabelSelector, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(j)
|
||||
// we can't have an entirely empty selector, so force
|
||||
// use of MatchExpression if necessary
|
||||
if len(j.MatchLabels) == 0 && len(j.MatchExpressions) == 0 {
|
||||
j.MatchExpressions = make([]metav1.LabelSelectorRequirement, c.Rand.Intn(2)+1)
|
||||
}
|
||||
|
||||
if j.MatchLabels != nil {
|
||||
fuzzedMatchLabels := make(map[string]string, len(j.MatchLabels))
|
||||
for i := 0; i < len(j.MatchLabels); i++ {
|
||||
fuzzedMatchLabels[randomLabelKey(c)] = randomLabelPart(c, true)
|
||||
}
|
||||
j.MatchLabels = fuzzedMatchLabels
|
||||
}
|
||||
|
||||
validOperators := []metav1.LabelSelectorOperator{
|
||||
metav1.LabelSelectorOpIn,
|
||||
metav1.LabelSelectorOpNotIn,
|
||||
metav1.LabelSelectorOpExists,
|
||||
metav1.LabelSelectorOpDoesNotExist,
|
||||
}
|
||||
|
||||
if j.MatchExpressions != nil {
|
||||
// NB: the label selector parser code sorts match expressions by key, and sorts the values,
|
||||
// so we need to make sure ours are sorted as well here to preserve round-trip comparision.
|
||||
// In practice, not sorting doesn't hurt anything...
|
||||
|
||||
for i := range j.MatchExpressions {
|
||||
req := metav1.LabelSelectorRequirement{}
|
||||
c.Fuzz(&req)
|
||||
req.Key = randomLabelKey(c)
|
||||
req.Operator = validOperators[c.Rand.Intn(len(validOperators))]
|
||||
if req.Operator == metav1.LabelSelectorOpIn || req.Operator == metav1.LabelSelectorOpNotIn {
|
||||
if len(req.Values) == 0 {
|
||||
// we must have some values here, so randomly choose a short length
|
||||
req.Values = make([]string, c.Rand.Intn(2)+1)
|
||||
}
|
||||
for i := range req.Values {
|
||||
req.Values[i] = randomLabelPart(c, true)
|
||||
}
|
||||
sort.Strings(req.Values)
|
||||
} else {
|
||||
req.Values = nil
|
||||
}
|
||||
j.MatchExpressions[i] = req
|
||||
}
|
||||
|
||||
sort.Slice(j.MatchExpressions, func(a, b int) bool { return j.MatchExpressions[a].Key < j.MatchExpressions[b].Key })
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func v1alpha1FuzzerFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
return []interface{}{
|
||||
func(r *metav1alpha1.TableRow, c fuzz.Continue) {
|
||||
c.Fuzz(&r.Object)
|
||||
c.Fuzz(&r.Conditions)
|
||||
if len(r.Conditions) == 0 {
|
||||
r.Conditions = nil
|
||||
}
|
||||
n := c.Intn(10)
|
||||
if n > 0 {
|
||||
r.Cells = make([]interface{}, n)
|
||||
}
|
||||
for i := range r.Cells {
|
||||
t := c.Intn(6)
|
||||
switch t {
|
||||
case 0:
|
||||
r.Cells[i] = c.RandString()
|
||||
case 1:
|
||||
r.Cells[i] = c.Uint64()
|
||||
case 2:
|
||||
r.Cells[i] = c.RandBool()
|
||||
case 3:
|
||||
x := map[string]interface{}{}
|
||||
for j := c.Intn(10) + 1; j >= 0; j-- {
|
||||
x[c.RandString()] = c.RandString()
|
||||
}
|
||||
r.Cells[i] = x
|
||||
case 4:
|
||||
x := make([]interface{}, c.Intn(10))
|
||||
for i := range x {
|
||||
x[i] = c.Uint64()
|
||||
}
|
||||
r.Cells[i] = x
|
||||
default:
|
||||
r.Cells[i] = nil
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var Funcs = fuzzer.MergeFuzzerFuncs(
|
||||
genericFuzzerFuncs,
|
||||
v1FuzzerFuncs,
|
||||
v1alpha1FuzzerFuncs,
|
||||
)
|
60
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/BUILD
generated
vendored
Normal file
60
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/BUILD
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"register_test.go",
|
||||
"roundtrip_test.go",
|
||||
],
|
||||
importpath = "k8s.io/apimachinery/pkg/apis/meta/internalversion",
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/testing/roundtrip:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/fuzzer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"conversion.go",
|
||||
"doc.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"zz_generated.conversion.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
],
|
||||
importpath = "k8s.io/apimachinery/pkg/apis/meta/internalversion",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
77
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/conversion.go
generated
vendored
Normal file
77
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/conversion.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright 2017 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 internalversion
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
func Convert_internalversion_ListOptions_To_v1_ListOptions(in *ListOptions, out *metav1.ListOptions, s conversion.Scope) error {
|
||||
if err := metav1.Convert_fields_Selector_To_string(&in.FieldSelector, &out.FieldSelector, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := metav1.Convert_labels_Selector_To_string(&in.LabelSelector, &out.LabelSelector, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.IncludeUninitialized = in.IncludeUninitialized
|
||||
out.ResourceVersion = in.ResourceVersion
|
||||
out.TimeoutSeconds = in.TimeoutSeconds
|
||||
out.Watch = in.Watch
|
||||
out.Limit = in.Limit
|
||||
out.Continue = in.Continue
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_ListOptions_To_internalversion_ListOptions(in *metav1.ListOptions, out *ListOptions, s conversion.Scope) error {
|
||||
if err := metav1.Convert_string_To_fields_Selector(&in.FieldSelector, &out.FieldSelector, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := metav1.Convert_string_To_labels_Selector(&in.LabelSelector, &out.LabelSelector, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.IncludeUninitialized = in.IncludeUninitialized
|
||||
out.ResourceVersion = in.ResourceVersion
|
||||
out.TimeoutSeconds = in.TimeoutSeconds
|
||||
out.Watch = in.Watch
|
||||
out.Limit = in.Limit
|
||||
out.Continue = in.Continue
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_map_to_v1_LabelSelector(in *map[string]string, out *metav1.LabelSelector, s conversion.Scope) error {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out = new(metav1.LabelSelector)
|
||||
for labelKey, labelValue := range *in {
|
||||
metav1.AddLabelToSelector(out, labelKey, labelValue)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_LabelSelector_to_map(in *metav1.LabelSelector, out *map[string]string, s conversion.Scope) error {
|
||||
var err error
|
||||
*out, err = metav1.LabelSelectorAsMap(in)
|
||||
if err != nil {
|
||||
err = field.Invalid(field.NewPath("labelSelector"), *in, fmt.Sprintf("cannot convert to old selector: %v", err))
|
||||
}
|
||||
return err
|
||||
}
|
19
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/doc.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2016 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.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
|
||||
package internalversion
|
105
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/register.go
generated
vendored
Normal file
105
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/register.go
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
Copyright 2017 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 internalversion
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1alpha1 "k8s.io/apimachinery/pkg/apis/meta/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
)
|
||||
|
||||
// GroupName is the group name for this API.
|
||||
const GroupName = "meta.k8s.io"
|
||||
|
||||
// Scheme is the registry for any type that adheres to the meta API spec.
|
||||
var scheme = runtime.NewScheme()
|
||||
|
||||
var (
|
||||
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
|
||||
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
|
||||
SchemeBuilder runtime.SchemeBuilder
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
AddToScheme = localSchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// Codecs provides access to encoding and decoding for the scheme.
|
||||
var Codecs = serializer.NewCodecFactory(scheme)
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
|
||||
|
||||
// ParameterCodec handles versioning of objects that are converted to query parameters.
|
||||
var ParameterCodec = runtime.NewParameterCodec(scheme)
|
||||
|
||||
// Kind takes an unqualified kind and returns a Group qualified GroupKind
|
||||
func Kind(kind string) schema.GroupKind {
|
||||
return SchemeGroupVersion.WithKind(kind).GroupKind()
|
||||
}
|
||||
|
||||
// addToGroupVersion registers common meta types into schemas.
|
||||
func addToGroupVersion(scheme *runtime.Scheme, groupVersion schema.GroupVersion) error {
|
||||
if err := scheme.AddIgnoredConversionType(&metav1.TypeMeta{}, &metav1.TypeMeta{}); err != nil {
|
||||
return err
|
||||
}
|
||||
scheme.AddConversionFuncs(
|
||||
metav1.Convert_string_To_labels_Selector,
|
||||
metav1.Convert_labels_Selector_To_string,
|
||||
|
||||
metav1.Convert_string_To_fields_Selector,
|
||||
metav1.Convert_fields_Selector_To_string,
|
||||
|
||||
Convert_map_to_v1_LabelSelector,
|
||||
Convert_v1_LabelSelector_to_map,
|
||||
|
||||
Convert_internalversion_ListOptions_To_v1_ListOptions,
|
||||
Convert_v1_ListOptions_To_internalversion_ListOptions,
|
||||
)
|
||||
// ListOptions is the only options struct which needs conversion (it exposes labels and fields
|
||||
// as selectors for convenience). The other types have only a single representation today.
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&ListOptions{},
|
||||
&metav1.GetOptions{},
|
||||
&metav1.ExportOptions{},
|
||||
&metav1.DeleteOptions{},
|
||||
)
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&metav1alpha1.Table{},
|
||||
&metav1alpha1.TableOptions{},
|
||||
&metav1alpha1.PartialObjectMetadata{},
|
||||
&metav1alpha1.PartialObjectMetadataList{},
|
||||
)
|
||||
scheme.AddKnownTypes(metav1alpha1.SchemeGroupVersion,
|
||||
&metav1alpha1.Table{},
|
||||
&metav1alpha1.TableOptions{},
|
||||
&metav1alpha1.PartialObjectMetadata{},
|
||||
&metav1alpha1.PartialObjectMetadataList{},
|
||||
)
|
||||
// Allow delete options to be decoded across all version in this scheme (we may want to be more clever than this)
|
||||
scheme.AddUnversionedTypes(SchemeGroupVersion, &metav1.DeleteOptions{})
|
||||
metav1.AddToGroupVersion(scheme, metav1.SchemeGroupVersion)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unlike other API groups, meta internal knows about all meta external versions, but keeps
|
||||
// the logic for conversion private.
|
||||
func init() {
|
||||
if err := addToGroupVersion(scheme, SchemeGroupVersion); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
89
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/register_test.go
generated
vendored
Normal file
89
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/register_test.go
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright 2017 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 internalversion
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
)
|
||||
|
||||
func TestListOptions(t *testing.T) {
|
||||
// verify round trip conversion
|
||||
ten := int64(10)
|
||||
in := &metav1.ListOptions{
|
||||
LabelSelector: "a=1",
|
||||
FieldSelector: "b=1",
|
||||
ResourceVersion: "10",
|
||||
TimeoutSeconds: &ten,
|
||||
Watch: true,
|
||||
}
|
||||
out := &ListOptions{}
|
||||
if err := scheme.Convert(in, out, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actual := &metav1.ListOptions{}
|
||||
if err := scheme.Convert(out, actual, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(in, actual) {
|
||||
t.Errorf("unexpected: %s", diff.ObjectReflectDiff(in, actual))
|
||||
}
|
||||
|
||||
// verify failing conversion
|
||||
for i, failingObject := range []*metav1.ListOptions{
|
||||
{LabelSelector: "a!!!"},
|
||||
{FieldSelector: "a!!!"},
|
||||
} {
|
||||
out = &ListOptions{}
|
||||
if err := scheme.Convert(failingObject, out, nil); err == nil {
|
||||
t.Errorf("%d: unexpected conversion: %#v", i, out)
|
||||
}
|
||||
}
|
||||
|
||||
// verify kind registration
|
||||
if gvks, unversioned, err := scheme.ObjectKinds(in); err != nil || unversioned || gvks[0] != metav1.SchemeGroupVersion.WithKind("ListOptions") {
|
||||
t.Errorf("unexpected: %v %v %v", gvks[0], unversioned, err)
|
||||
}
|
||||
if gvks, unversioned, err := scheme.ObjectKinds(out); err != nil || unversioned || gvks[0] != SchemeGroupVersion.WithKind("ListOptions") {
|
||||
t.Errorf("unexpected: %v %v %v", gvks[0], unversioned, err)
|
||||
}
|
||||
|
||||
actual = &metav1.ListOptions{}
|
||||
if err := ParameterCodec.DecodeParameters(url.Values{"watch": []string{"1"}}, metav1.SchemeGroupVersion, actual); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !actual.Watch {
|
||||
t.Errorf("unexpected watch decode: %#v", actual)
|
||||
}
|
||||
|
||||
// check ParameterCodec
|
||||
query, err := ParameterCodec.EncodeParameters(in, metav1.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actual = &metav1.ListOptions{}
|
||||
if err := ParameterCodec.DecodeParameters(query, metav1.SchemeGroupVersion, actual); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(in, actual) {
|
||||
t.Errorf("unexpected: %s", diff.ObjectReflectDiff(in, actual))
|
||||
}
|
||||
}
|
28
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/roundtrip_test.go
generated
vendored
Normal file
28
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/roundtrip_test.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
Copyright 2017 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 internalversion
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/testing/roundtrip"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/fuzzer"
|
||||
)
|
||||
|
||||
func TestRoundTrip(t *testing.T) {
|
||||
roundtrip.RoundTripTestForScheme(t, scheme, fuzzer.Funcs)
|
||||
}
|
70
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/types.go
generated
vendored
Normal file
70
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/types.go
generated
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright 2017 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 internalversion
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// ListOptions is the query options to a standard REST list call.
|
||||
type ListOptions struct {
|
||||
metav1.TypeMeta
|
||||
|
||||
// A selector based on labels
|
||||
LabelSelector labels.Selector
|
||||
// A selector based on fields
|
||||
FieldSelector fields.Selector
|
||||
// If true, partially initialized resources are included in the response.
|
||||
// +optional
|
||||
IncludeUninitialized bool
|
||||
// If true, watch for changes to this list
|
||||
Watch bool
|
||||
// When specified with a watch call, shows changes that occur after that particular version of a resource.
|
||||
// Defaults to changes from the beginning of history.
|
||||
// When specified for list:
|
||||
// - if unset, then the result is returned from remote storage based on quorum-read flag;
|
||||
// - if it's 0, then we simply return what we currently have in cache, no guarantee;
|
||||
// - if set to non zero, then the result is at least as fresh as given rv.
|
||||
ResourceVersion string
|
||||
// Timeout for the list/watch call.
|
||||
TimeoutSeconds *int64
|
||||
// Limit specifies the maximum number of results to return from the server. The server may
|
||||
// not support this field on all resource types, but if it does and more results remain it
|
||||
// will set the continue field on the returned list object.
|
||||
Limit int64
|
||||
// Continue is a token returned by the server that lets a client retrieve chunks of results
|
||||
// from the server by specifying limit. The server may reject requests for continuation tokens
|
||||
// it does not recognize and will return a 410 error if the token can no longer be used because
|
||||
// it has expired.
|
||||
Continue string
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// List holds a list of objects, which may not be known by the server.
|
||||
type List struct {
|
||||
metav1.TypeMeta
|
||||
// +optional
|
||||
metav1.ListMeta
|
||||
|
||||
Items []runtime.Object
|
||||
}
|
113
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/zz_generated.conversion.go
generated
vendored
Normal file
113
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/zz_generated.conversion.go
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2017 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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by conversion-gen. Do not edit it manually!
|
||||
|
||||
package internalversion
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
localSchemeBuilder.Register(RegisterConversions)
|
||||
}
|
||||
|
||||
// RegisterConversions adds conversion functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterConversions(scheme *runtime.Scheme) error {
|
||||
return scheme.AddGeneratedConversionFuncs(
|
||||
Convert_internalversion_List_To_v1_List,
|
||||
Convert_v1_List_To_internalversion_List,
|
||||
Convert_internalversion_ListOptions_To_v1_ListOptions,
|
||||
Convert_v1_ListOptions_To_internalversion_ListOptions,
|
||||
)
|
||||
}
|
||||
|
||||
func autoConvert_internalversion_List_To_v1_List(in *List, out *v1.List, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]runtime.RawExtension, len(*in))
|
||||
for i := range *in {
|
||||
if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = make([]runtime.RawExtension, 0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_internalversion_List_To_v1_List is an autogenerated conversion function.
|
||||
func Convert_internalversion_List_To_v1_List(in *List, out *v1.List, s conversion.Scope) error {
|
||||
return autoConvert_internalversion_List_To_v1_List(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_List_To_internalversion_List(in *v1.List, out *List, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]runtime.Object, len(*in))
|
||||
for i := range *in {
|
||||
if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_List_To_internalversion_List is an autogenerated conversion function.
|
||||
func Convert_v1_List_To_internalversion_List(in *v1.List, out *List, s conversion.Scope) error {
|
||||
return autoConvert_v1_List_To_internalversion_List(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_internalversion_ListOptions_To_v1_ListOptions(in *ListOptions, out *v1.ListOptions, s conversion.Scope) error {
|
||||
if err := v1.Convert_labels_Selector_To_string(&in.LabelSelector, &out.LabelSelector, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_fields_Selector_To_string(&in.FieldSelector, &out.FieldSelector, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.IncludeUninitialized = in.IncludeUninitialized
|
||||
out.Watch = in.Watch
|
||||
out.ResourceVersion = in.ResourceVersion
|
||||
out.TimeoutSeconds = (*int64)(unsafe.Pointer(in.TimeoutSeconds))
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1_ListOptions_To_internalversion_ListOptions(in *v1.ListOptions, out *ListOptions, s conversion.Scope) error {
|
||||
if err := v1.Convert_string_To_labels_Selector(&in.LabelSelector, &out.LabelSelector, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_string_To_fields_Selector(&in.FieldSelector, &out.FieldSelector, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.IncludeUninitialized = in.IncludeUninitialized
|
||||
out.Watch = in.Watch
|
||||
out.ResourceVersion = in.ResourceVersion
|
||||
out.TimeoutSeconds = (*int64)(unsafe.Pointer(in.TimeoutSeconds))
|
||||
return nil
|
||||
}
|
108
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/zz_generated.deepcopy.go
generated
vendored
Normal file
108
vendor/k8s.io/apimachinery/pkg/apis/meta/internalversion/zz_generated.deepcopy.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2017 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.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package internalversion
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *List) DeepCopyInto(out *List) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
out.ListMeta = in.ListMeta
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]runtime.Object, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] == nil {
|
||||
(*out)[i] = nil
|
||||
} else {
|
||||
(*out)[i] = (*in)[i].DeepCopyObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new List.
|
||||
func (in *List) DeepCopy() *List {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(List)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *List) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ListOptions) DeepCopyInto(out *ListOptions) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.LabelSelector == nil {
|
||||
out.LabelSelector = nil
|
||||
} else {
|
||||
out.LabelSelector = in.LabelSelector.DeepCopySelector()
|
||||
}
|
||||
if in.FieldSelector == nil {
|
||||
out.FieldSelector = nil
|
||||
} else {
|
||||
out.FieldSelector = in.FieldSelector.DeepCopySelector()
|
||||
}
|
||||
if in.TimeoutSeconds != nil {
|
||||
in, out := &in.TimeoutSeconds, &out.TimeoutSeconds
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ListOptions.
|
||||
func (in *ListOptions) DeepCopy() *ListOptions {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ListOptions)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ListOptions) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
105
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/BUILD
generated
vendored
Normal file
105
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/BUILD
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"controller_ref_test.go",
|
||||
"duration_test.go",
|
||||
"group_version_test.go",
|
||||
"helpers_test.go",
|
||||
"labels_test.go",
|
||||
"micro_time_test.go",
|
||||
"time_test.go",
|
||||
"types_test.go",
|
||||
],
|
||||
importpath = "k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/github.com/ghodss/yaml:go_default_library",
|
||||
"//vendor/github.com/json-iterator/go:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"controller_ref.go",
|
||||
"conversion.go",
|
||||
"doc.go",
|
||||
"duration.go",
|
||||
"generated.pb.go",
|
||||
"group_version.go",
|
||||
"helpers.go",
|
||||
"labels.go",
|
||||
"meta.go",
|
||||
"micro_time.go",
|
||||
"micro_time_proto.go",
|
||||
"register.go",
|
||||
"time.go",
|
||||
"time_proto.go",
|
||||
"types.go",
|
||||
"types_swagger_doc_generated.go",
|
||||
"watch.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
"zz_generated.defaults.go",
|
||||
],
|
||||
importpath = "k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
deps = [
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/gogo/protobuf/sortkeys:go_default_library",
|
||||
"//vendor/github.com/google/gofuzz:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/selection:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/kube-openapi/pkg/common:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:all-srcs",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "go_default_library_protos",
|
||||
srcs = ["generated.proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_xtest",
|
||||
srcs = ["conversion_test.go"],
|
||||
importpath = "k8s.io/apimachinery/pkg/apis/meta/v1_test",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
],
|
||||
)
|
32
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/OWNERS
generated
vendored
Executable file
32
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/OWNERS
generated
vendored
Executable file
@ -0,0 +1,32 @@
|
||||
reviewers:
|
||||
- thockin
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- brendandburns
|
||||
- caesarxuchao
|
||||
- liggitt
|
||||
- nikhiljindal
|
||||
- gmarek
|
||||
- erictune
|
||||
- davidopp
|
||||
- sttts
|
||||
- quinton-hoole
|
||||
- luxas
|
||||
- janetkuo
|
||||
- justinsb
|
||||
- ncdc
|
||||
- timothysc
|
||||
- soltysh
|
||||
- dims
|
||||
- madhusudancs
|
||||
- hongchaodeng
|
||||
- krousey
|
||||
- mml
|
||||
- mbohlool
|
||||
- david-mcmahon
|
||||
- therc
|
||||
- mqliang
|
||||
- kevin-wangzefeng
|
||||
- jianhuiz
|
||||
- feihujiang
|
54
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/controller_ref.go
generated
vendored
Normal file
54
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/controller_ref.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright 2017 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 (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// IsControlledBy checks if the object has a controllerRef set to the given owner
|
||||
func IsControlledBy(obj Object, owner Object) bool {
|
||||
ref := GetControllerOf(obj)
|
||||
if ref == nil {
|
||||
return false
|
||||
}
|
||||
return ref.UID == owner.GetUID()
|
||||
}
|
||||
|
||||
// GetControllerOf returns a pointer to a copy of the controllerRef if controllee has a controller
|
||||
func GetControllerOf(controllee Object) *OwnerReference {
|
||||
for _, ref := range controllee.GetOwnerReferences() {
|
||||
if ref.Controller != nil && *ref.Controller {
|
||||
return &ref
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewControllerRef creates an OwnerReference pointing to the given owner.
|
||||
func NewControllerRef(owner Object, gvk schema.GroupVersionKind) *OwnerReference {
|
||||
blockOwnerDeletion := true
|
||||
isController := true
|
||||
return &OwnerReference{
|
||||
APIVersion: gvk.GroupVersion().String(),
|
||||
Kind: gvk.Kind,
|
||||
Name: owner.GetName(),
|
||||
UID: owner.GetUID(),
|
||||
BlockOwnerDeletion: &blockOwnerDeletion,
|
||||
Controller: &isController,
|
||||
}
|
||||
}
|
133
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/controller_ref_test.go
generated
vendored
Normal file
133
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/controller_ref_test.go
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
Copyright 2017 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 (
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
type metaObj struct {
|
||||
ObjectMeta
|
||||
TypeMeta
|
||||
}
|
||||
|
||||
func TestNewControllerRef(t *testing.T) {
|
||||
gvk := schema.GroupVersionKind{
|
||||
Group: "group",
|
||||
Version: "v1",
|
||||
Kind: "Kind",
|
||||
}
|
||||
obj1 := &metaObj{
|
||||
ObjectMeta: ObjectMeta{
|
||||
Name: "name",
|
||||
UID: "uid1",
|
||||
},
|
||||
}
|
||||
controllerRef := NewControllerRef(obj1, gvk)
|
||||
if controllerRef.UID != obj1.UID {
|
||||
t.Errorf("Incorrect UID: %s", controllerRef.UID)
|
||||
}
|
||||
if controllerRef.Controller == nil || *controllerRef.Controller != true {
|
||||
t.Error("Controller must be set to true")
|
||||
}
|
||||
if controllerRef.BlockOwnerDeletion == nil || *controllerRef.BlockOwnerDeletion != true {
|
||||
t.Error("BlockOwnerDeletion must be set to true")
|
||||
}
|
||||
if controllerRef.APIVersion == "" ||
|
||||
controllerRef.Kind == "" ||
|
||||
controllerRef.Name == "" {
|
||||
t.Errorf("All controllerRef fields must be set: %v", controllerRef)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetControllerOf(t *testing.T) {
|
||||
gvk := schema.GroupVersionKind{
|
||||
Group: "group",
|
||||
Version: "v1",
|
||||
Kind: "Kind",
|
||||
}
|
||||
obj1 := &metaObj{
|
||||
ObjectMeta: ObjectMeta{
|
||||
UID: "uid1",
|
||||
Name: "name1",
|
||||
},
|
||||
}
|
||||
controllerRef := NewControllerRef(obj1, gvk)
|
||||
var falseRef = false
|
||||
obj2 := &metaObj{
|
||||
ObjectMeta: ObjectMeta{
|
||||
UID: "uid2",
|
||||
Name: "name1",
|
||||
OwnerReferences: []OwnerReference{
|
||||
{
|
||||
Name: "owner1",
|
||||
Controller: &falseRef,
|
||||
},
|
||||
*controllerRef,
|
||||
{
|
||||
Name: "owner2",
|
||||
Controller: &falseRef,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if GetControllerOf(obj1) != nil {
|
||||
t.Error("GetControllerOf must return null")
|
||||
}
|
||||
c := GetControllerOf(obj2)
|
||||
if c.Name != controllerRef.Name || c.UID != controllerRef.UID {
|
||||
t.Errorf("Incorrect result of GetControllerOf: %v", c)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsControlledBy(t *testing.T) {
|
||||
gvk := schema.GroupVersionKind{
|
||||
Group: "group",
|
||||
Version: "v1",
|
||||
Kind: "Kind",
|
||||
}
|
||||
obj1 := &metaObj{
|
||||
ObjectMeta: ObjectMeta{
|
||||
UID: "uid1",
|
||||
},
|
||||
}
|
||||
obj2 := &metaObj{
|
||||
ObjectMeta: ObjectMeta{
|
||||
UID: "uid2",
|
||||
OwnerReferences: []OwnerReference{
|
||||
*NewControllerRef(obj1, gvk),
|
||||
},
|
||||
},
|
||||
}
|
||||
obj3 := &metaObj{
|
||||
ObjectMeta: ObjectMeta{
|
||||
UID: "uid3",
|
||||
OwnerReferences: []OwnerReference{
|
||||
*NewControllerRef(obj2, gvk),
|
||||
},
|
||||
},
|
||||
}
|
||||
if !IsControlledBy(obj2, obj1) || !IsControlledBy(obj3, obj2) {
|
||||
t.Error("Incorrect IsControlledBy result: false")
|
||||
}
|
||||
if IsControlledBy(obj3, obj1) {
|
||||
t.Error("Incorrect IsControlledBy result: true")
|
||||
}
|
||||
}
|
288
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/conversion.go
generated
vendored
Normal file
288
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/conversion.go
generated
vendored
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
Copyright 2014 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 (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func AddConversionFuncs(scheme *runtime.Scheme) error {
|
||||
return scheme.AddConversionFuncs(
|
||||
Convert_v1_TypeMeta_To_v1_TypeMeta,
|
||||
|
||||
Convert_unversioned_ListMeta_To_unversioned_ListMeta,
|
||||
|
||||
Convert_intstr_IntOrString_To_intstr_IntOrString,
|
||||
|
||||
Convert_unversioned_Time_To_unversioned_Time,
|
||||
Convert_unversioned_MicroTime_To_unversioned_MicroTime,
|
||||
|
||||
Convert_Pointer_v1_Duration_To_v1_Duration,
|
||||
Convert_v1_Duration_To_Pointer_v1_Duration,
|
||||
|
||||
Convert_Slice_string_To_unversioned_Time,
|
||||
|
||||
Convert_resource_Quantity_To_resource_Quantity,
|
||||
|
||||
Convert_string_To_labels_Selector,
|
||||
Convert_labels_Selector_To_string,
|
||||
|
||||
Convert_string_To_fields_Selector,
|
||||
Convert_fields_Selector_To_string,
|
||||
|
||||
Convert_Pointer_bool_To_bool,
|
||||
Convert_bool_To_Pointer_bool,
|
||||
|
||||
Convert_Pointer_string_To_string,
|
||||
Convert_string_To_Pointer_string,
|
||||
|
||||
Convert_Pointer_int64_To_int,
|
||||
Convert_int_To_Pointer_int64,
|
||||
|
||||
Convert_Pointer_int32_To_int32,
|
||||
Convert_int32_To_Pointer_int32,
|
||||
|
||||
Convert_Pointer_float64_To_float64,
|
||||
Convert_float64_To_Pointer_float64,
|
||||
|
||||
Convert_map_to_unversioned_LabelSelector,
|
||||
Convert_unversioned_LabelSelector_to_map,
|
||||
|
||||
Convert_Slice_string_To_Slice_int32,
|
||||
)
|
||||
}
|
||||
|
||||
func Convert_Pointer_float64_To_float64(in **float64, out *float64, s conversion.Scope) error {
|
||||
if *in == nil {
|
||||
*out = 0
|
||||
return nil
|
||||
}
|
||||
*out = float64(**in)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_float64_To_Pointer_float64(in *float64, out **float64, s conversion.Scope) error {
|
||||
temp := float64(*in)
|
||||
*out = &temp
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_Pointer_int32_To_int32(in **int32, out *int32, s conversion.Scope) error {
|
||||
if *in == nil {
|
||||
*out = 0
|
||||
return nil
|
||||
}
|
||||
*out = int32(**in)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_int32_To_Pointer_int32(in *int32, out **int32, s conversion.Scope) error {
|
||||
temp := int32(*in)
|
||||
*out = &temp
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_Pointer_int64_To_int(in **int64, out *int, s conversion.Scope) error {
|
||||
if *in == nil {
|
||||
*out = 0
|
||||
return nil
|
||||
}
|
||||
*out = int(**in)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_int_To_Pointer_int64(in *int, out **int64, s conversion.Scope) error {
|
||||
temp := int64(*in)
|
||||
*out = &temp
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_Pointer_string_To_string(in **string, out *string, s conversion.Scope) error {
|
||||
if *in == nil {
|
||||
*out = ""
|
||||
return nil
|
||||
}
|
||||
*out = **in
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_string_To_Pointer_string(in *string, out **string, s conversion.Scope) error {
|
||||
if in == nil {
|
||||
stringVar := ""
|
||||
*out = &stringVar
|
||||
return nil
|
||||
}
|
||||
*out = in
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_Pointer_bool_To_bool(in **bool, out *bool, s conversion.Scope) error {
|
||||
if *in == nil {
|
||||
*out = false
|
||||
return nil
|
||||
}
|
||||
*out = **in
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_bool_To_Pointer_bool(in *bool, out **bool, s conversion.Scope) error {
|
||||
if in == nil {
|
||||
boolVar := false
|
||||
*out = &boolVar
|
||||
return nil
|
||||
}
|
||||
*out = in
|
||||
return nil
|
||||
}
|
||||
|
||||
// +k8s:conversion-fn=drop
|
||||
func Convert_v1_TypeMeta_To_v1_TypeMeta(in, out *TypeMeta, s conversion.Scope) error {
|
||||
// These values are explicitly not copied
|
||||
//out.APIVersion = in.APIVersion
|
||||
//out.Kind = in.Kind
|
||||
return nil
|
||||
}
|
||||
|
||||
// +k8s:conversion-fn=copy-only
|
||||
func Convert_unversioned_ListMeta_To_unversioned_ListMeta(in, out *ListMeta, s conversion.Scope) error {
|
||||
*out = *in
|
||||
return nil
|
||||
}
|
||||
|
||||
// +k8s:conversion-fn=copy-only
|
||||
func Convert_intstr_IntOrString_To_intstr_IntOrString(in, out *intstr.IntOrString, s conversion.Scope) error {
|
||||
*out = *in
|
||||
return nil
|
||||
}
|
||||
|
||||
// +k8s:conversion-fn=copy-only
|
||||
func Convert_unversioned_Time_To_unversioned_Time(in *Time, out *Time, s conversion.Scope) error {
|
||||
// Cannot deep copy these, because time.Time has unexported fields.
|
||||
*out = *in
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_Pointer_v1_Duration_To_v1_Duration(in **Duration, out *Duration, s conversion.Scope) error {
|
||||
if *in == nil {
|
||||
*out = Duration{} // zero duration
|
||||
return nil
|
||||
}
|
||||
*out = **in // copy
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_Duration_To_Pointer_v1_Duration(in *Duration, out **Duration, s conversion.Scope) error {
|
||||
temp := *in //copy
|
||||
*out = &temp
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_unversioned_MicroTime_To_unversioned_MicroTime(in *MicroTime, out *MicroTime, s conversion.Scope) error {
|
||||
// Cannot deep copy these, because time.Time has unexported fields.
|
||||
*out = *in
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_Slice_string_To_unversioned_Time allows converting a URL query parameter value
|
||||
func Convert_Slice_string_To_unversioned_Time(input *[]string, out *Time, s conversion.Scope) error {
|
||||
str := ""
|
||||
if len(*input) > 0 {
|
||||
str = (*input)[0]
|
||||
}
|
||||
return out.UnmarshalQueryParameter(str)
|
||||
}
|
||||
|
||||
func Convert_string_To_labels_Selector(in *string, out *labels.Selector, s conversion.Scope) error {
|
||||
selector, err := labels.Parse(*in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*out = selector
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_string_To_fields_Selector(in *string, out *fields.Selector, s conversion.Scope) error {
|
||||
selector, err := fields.ParseSelector(*in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*out = selector
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_labels_Selector_To_string(in *labels.Selector, out *string, s conversion.Scope) error {
|
||||
if *in == nil {
|
||||
return nil
|
||||
}
|
||||
*out = (*in).String()
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_fields_Selector_To_string(in *fields.Selector, out *string, s conversion.Scope) error {
|
||||
if *in == nil {
|
||||
return nil
|
||||
}
|
||||
*out = (*in).String()
|
||||
return nil
|
||||
}
|
||||
|
||||
// +k8s:conversion-fn=copy-only
|
||||
func Convert_resource_Quantity_To_resource_Quantity(in *resource.Quantity, out *resource.Quantity, s conversion.Scope) error {
|
||||
*out = *in
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_map_to_unversioned_LabelSelector(in *map[string]string, out *LabelSelector, s conversion.Scope) error {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
for labelKey, labelValue := range *in {
|
||||
AddLabelToSelector(out, labelKey, labelValue)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_unversioned_LabelSelector_to_map(in *LabelSelector, out *map[string]string, s conversion.Scope) error {
|
||||
var err error
|
||||
*out, err = LabelSelectorAsMap(in)
|
||||
return err
|
||||
}
|
||||
|
||||
// Convert_Slice_string_To_Slice_int32 converts multiple query parameters or
|
||||
// a single query parameter with a comma delimited value to multiple int32.
|
||||
// This is used for port forwarding which needs the ports as int32.
|
||||
func Convert_Slice_string_To_Slice_int32(in *[]string, out *[]int32, s conversion.Scope) error {
|
||||
for _, s := range *in {
|
||||
for _, v := range strings.Split(s, ",") {
|
||||
x, err := strconv.ParseUint(v, 10, 16)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot convert to []int32: %v", err)
|
||||
}
|
||||
*out = append(*out, int32(x))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
49
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/conversion_test.go
generated
vendored
Normal file
49
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/conversion_test.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright 2017 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_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestMapToLabelSelectorRoundTrip(t *testing.T) {
|
||||
// We should be able to round-trip a map-only selector through LabelSelector.
|
||||
inputs := []map[string]string{
|
||||
nil,
|
||||
{},
|
||||
{"one": "foo"},
|
||||
{"one": "foo", "two": "bar"},
|
||||
}
|
||||
for _, in := range inputs {
|
||||
ls := &v1.LabelSelector{}
|
||||
if err := v1.Convert_map_to_unversioned_LabelSelector(&in, ls, nil); err != nil {
|
||||
t.Errorf("Convert_map_to_unversioned_LabelSelector(%#v): %v", in, err)
|
||||
continue
|
||||
}
|
||||
out := map[string]string{}
|
||||
if err := v1.Convert_unversioned_LabelSelector_to_map(ls, &out, nil); err != nil {
|
||||
t.Errorf("Convert_unversioned_LabelSelector_to_map(%#v): %v", ls, err)
|
||||
continue
|
||||
}
|
||||
if !apiequality.Semantic.DeepEqual(in, out) {
|
||||
t.Errorf("map-selector conversion round-trip failed: got %v; want %v", out, in)
|
||||
}
|
||||
}
|
||||
}
|
22
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/doc.go
generated
vendored
Normal file
22
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/doc.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright 2016 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.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
|
||||
// +groupName=meta.k8s.io
|
||||
package v1 // import "k8s.io/apimachinery/pkg/apis/meta/v1"
|
47
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/duration.go
generated
vendored
Normal file
47
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/duration.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2014 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"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Duration is a wrapper around time.Duration which supports correct
|
||||
// marshaling to YAML and JSON. In particular, it marshals into strings, which
|
||||
// can be used as map keys in json.
|
||||
type Duration struct {
|
||||
time.Duration `protobuf:"varint,1,opt,name=duration,casttype=time.Duration"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaller interface.
|
||||
func (d *Duration) UnmarshalJSON(b []byte) error {
|
||||
var str string
|
||||
json.Unmarshal(b, &str)
|
||||
|
||||
pd, err := time.ParseDuration(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Duration = pd
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (d Duration) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(d.Duration.String())
|
||||
}
|
153
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/duration_test.go
generated
vendored
Normal file
153
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/duration_test.go
generated
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
Copyright 2014 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"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
)
|
||||
|
||||
type DurationHolder struct {
|
||||
D Duration `json:"d"`
|
||||
}
|
||||
|
||||
func TestDurationMarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input Duration
|
||||
result string
|
||||
}{
|
||||
{Duration{5 * time.Second}, "d: 5s\n"},
|
||||
{Duration{2 * time.Minute}, "d: 2m0s\n"},
|
||||
{Duration{time.Hour + 3*time.Millisecond}, "d: 1h0m0.003s\n"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := DurationHolder{c.input}
|
||||
result, err := yaml.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal input: %q: %v", input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal input: %q: expected %q, got %q", input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDurationUnmarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result Duration
|
||||
}{
|
||||
{"d: 0s\n", Duration{}},
|
||||
{"d: 5s\n", Duration{5 * time.Second}},
|
||||
{"d: 2m0s\n", Duration{2 * time.Minute}},
|
||||
{"d: 1h0m0.003s\n", Duration{time.Hour + 3*time.Millisecond}},
|
||||
|
||||
// Units with zero values can optionally be dropped
|
||||
{"d: 2m\n", Duration{2 * time.Minute}},
|
||||
{"d: 1h0.003s\n", Duration{time.Hour + 3*time.Millisecond}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result DurationHolder
|
||||
if err := yaml.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal input %q: %v", c.input, err)
|
||||
}
|
||||
if result.D != c.result {
|
||||
t.Errorf("Failed to unmarshal input %q: expected %q, got %q", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDurationMarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input Duration
|
||||
result string
|
||||
}{
|
||||
{Duration{5 * time.Second}, `{"d":"5s"}`},
|
||||
{Duration{2 * time.Minute}, `{"d":"2m0s"}`},
|
||||
{Duration{time.Hour + 3*time.Millisecond}, `{"d":"1h0m0.003s"}`},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := DurationHolder{c.input}
|
||||
result, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal input: %q: %v", input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal input: %q: expected %q, got %q", input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDurationUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result Duration
|
||||
}{
|
||||
{`{"d":"0s"}`, Duration{}},
|
||||
{`{"d":"5s"}`, Duration{5 * time.Second}},
|
||||
{`{"d":"2m0s"}`, Duration{2 * time.Minute}},
|
||||
{`{"d":"1h0m0.003s"}`, Duration{time.Hour + 3*time.Millisecond}},
|
||||
|
||||
// Units with zero values can optionally be dropped
|
||||
{`{"d":"2m"}`, Duration{2 * time.Minute}},
|
||||
{`{"d":"1h0.003s"}`, Duration{time.Hour + 3*time.Millisecond}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result DurationHolder
|
||||
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal input %q: %v", c.input, err)
|
||||
}
|
||||
if result.D != c.result {
|
||||
t.Errorf("Failed to unmarshal input %q: expected %q, got %q", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDurationMarshalJSONUnmarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input Duration
|
||||
}{
|
||||
{Duration{}},
|
||||
{Duration{5 * time.Second}},
|
||||
{Duration{2 * time.Minute}},
|
||||
{Duration{time.Hour + 3*time.Millisecond}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
input := DurationHolder{c.input}
|
||||
jsonMarshalled, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("%d-1: Failed to marshal input: '%v': %v", i, input, err)
|
||||
}
|
||||
|
||||
var result DurationHolder
|
||||
if err := yaml.Unmarshal(jsonMarshalled, &result); err != nil {
|
||||
t.Errorf("%d-2: Failed to unmarshal '%+v': %v", i, string(jsonMarshalled), err)
|
||||
}
|
||||
|
||||
if input.D != result.D {
|
||||
t.Errorf("%d-4: Failed to marshal input '%#v': got %#v", i, input, result)
|
||||
}
|
||||
}
|
||||
}
|
7961
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/generated.pb.go
generated
vendored
Normal file
7961
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/generated.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
837
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto
generated
vendored
Normal file
837
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto
generated
vendored
Normal file
@ -0,0 +1,837 @@
|
||||
/*
|
||||
Copyright 2017 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.
|
||||
*/
|
||||
|
||||
|
||||
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
|
||||
|
||||
syntax = 'proto2';
|
||||
|
||||
package k8s.io.apimachinery.pkg.apis.meta.v1;
|
||||
|
||||
import "k8s.io/apimachinery/pkg/runtime/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/util/intstr/generated.proto";
|
||||
|
||||
// Package-wide variables from generator "generated".
|
||||
option go_package = "v1";
|
||||
|
||||
// APIGroup contains the name, the supported versions, and the preferred version
|
||||
// of a group.
|
||||
message APIGroup {
|
||||
// name is the name of the group.
|
||||
optional string name = 1;
|
||||
|
||||
// versions are the versions supported in this group.
|
||||
repeated GroupVersionForDiscovery versions = 2;
|
||||
|
||||
// preferredVersion is the version preferred by the API server, which
|
||||
// probably is the storage version.
|
||||
// +optional
|
||||
optional GroupVersionForDiscovery preferredVersion = 3;
|
||||
|
||||
// a map of client CIDR to server address that is serving this group.
|
||||
// This is to help clients reach servers in the most network-efficient way possible.
|
||||
// Clients can use the appropriate server address as per the CIDR that they match.
|
||||
// In case of multiple matches, clients should use the longest matching CIDR.
|
||||
// The server returns only those CIDRs that it thinks that the client can match.
|
||||
// For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP.
|
||||
// Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP.
|
||||
repeated ServerAddressByClientCIDR serverAddressByClientCIDRs = 4;
|
||||
}
|
||||
|
||||
// APIGroupList is a list of APIGroup, to allow clients to discover the API at
|
||||
// /apis.
|
||||
message APIGroupList {
|
||||
// groups is a list of APIGroup.
|
||||
repeated APIGroup groups = 1;
|
||||
}
|
||||
|
||||
// APIResource specifies the name of a resource and whether it is namespaced.
|
||||
message APIResource {
|
||||
// name is the plural name of the resource.
|
||||
optional string name = 1;
|
||||
|
||||
// singularName is the singular name of the resource. This allows clients to handle plural and singular opaquely.
|
||||
// The singularName is more correct for reporting status on a single item and both singular and plural are allowed
|
||||
// from the kubectl CLI interface.
|
||||
optional string singularName = 6;
|
||||
|
||||
// namespaced indicates if a resource is namespaced or not.
|
||||
optional bool namespaced = 2;
|
||||
|
||||
// group is the preferred group of the resource. Empty implies the group of the containing resource list.
|
||||
// For subresources, this may have a different value, for example: Scale".
|
||||
optional string group = 8;
|
||||
|
||||
// version is the preferred version of the resource. Empty implies the version of the containing resource list
|
||||
// For subresources, this may have a different value, for example: v1 (while inside a v1beta1 version of the core resource's group)".
|
||||
optional string version = 9;
|
||||
|
||||
// kind is the kind for the resource (e.g. 'Foo' is the kind for a resource 'foo')
|
||||
optional string kind = 3;
|
||||
|
||||
// verbs is a list of supported kube verbs (this includes get, list, watch, create,
|
||||
// update, patch, delete, deletecollection, and proxy)
|
||||
optional Verbs verbs = 4;
|
||||
|
||||
// shortNames is a list of suggested short names of the resource.
|
||||
repeated string shortNames = 5;
|
||||
|
||||
// categories is a list of the grouped resources this resource belongs to (e.g. 'all')
|
||||
repeated string categories = 7;
|
||||
}
|
||||
|
||||
// APIResourceList is a list of APIResource, it is used to expose the name of the
|
||||
// resources supported in a specific group and version, and if the resource
|
||||
// is namespaced.
|
||||
message APIResourceList {
|
||||
// groupVersion is the group and version this APIResourceList is for.
|
||||
optional string groupVersion = 1;
|
||||
|
||||
// resources contains the name of the resources and if they are namespaced.
|
||||
repeated APIResource resources = 2;
|
||||
}
|
||||
|
||||
// APIVersions lists the versions that are available, to allow clients to
|
||||
// discover the API at /api, which is the root path of the legacy v1 API.
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
message APIVersions {
|
||||
// versions are the api versions that are available.
|
||||
repeated string versions = 1;
|
||||
|
||||
// a map of client CIDR to server address that is serving this group.
|
||||
// This is to help clients reach servers in the most network-efficient way possible.
|
||||
// Clients can use the appropriate server address as per the CIDR that they match.
|
||||
// In case of multiple matches, clients should use the longest matching CIDR.
|
||||
// The server returns only those CIDRs that it thinks that the client can match.
|
||||
// For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP.
|
||||
// Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP.
|
||||
repeated ServerAddressByClientCIDR serverAddressByClientCIDRs = 2;
|
||||
}
|
||||
|
||||
// DeleteOptions may be provided when deleting an API object.
|
||||
message DeleteOptions {
|
||||
// The duration in seconds before the object should be deleted. Value must be non-negative integer.
|
||||
// The value zero indicates delete immediately. If this value is nil, the default grace period for the
|
||||
// specified type will be used.
|
||||
// Defaults to a per object value if not specified. zero means delete immediately.
|
||||
// +optional
|
||||
optional int64 gracePeriodSeconds = 1;
|
||||
|
||||
// Must be fulfilled before a deletion is carried out. If not possible, a 409 Conflict status will be
|
||||
// returned.
|
||||
// +optional
|
||||
optional Preconditions preconditions = 2;
|
||||
|
||||
// Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7.
|
||||
// Should the dependent objects be orphaned. If true/false, the "orphan"
|
||||
// finalizer will be added to/removed from the object's finalizers list.
|
||||
// Either this field or PropagationPolicy may be set, but not both.
|
||||
// +optional
|
||||
optional bool orphanDependents = 3;
|
||||
|
||||
// Whether and how garbage collection will be performed.
|
||||
// Either this field or OrphanDependents may be set, but not both.
|
||||
// The default policy is decided by the existing finalizer set in the
|
||||
// metadata.finalizers and the resource-specific default policy.
|
||||
// Acceptable values are: 'Orphan' - orphan the dependents; 'Background' -
|
||||
// allow the garbage collector to delete the dependents in the background;
|
||||
// 'Foreground' - a cascading policy that deletes all dependents in the
|
||||
// foreground.
|
||||
// +optional
|
||||
optional string propagationPolicy = 4;
|
||||
}
|
||||
|
||||
// Duration is a wrapper around time.Duration which supports correct
|
||||
// marshaling to YAML and JSON. In particular, it marshals into strings, which
|
||||
// can be used as map keys in json.
|
||||
message Duration {
|
||||
optional int64 duration = 1;
|
||||
}
|
||||
|
||||
// ExportOptions is the query options to the standard REST get call.
|
||||
message ExportOptions {
|
||||
// Should this value be exported. Export strips fields that a user can not specify.
|
||||
optional bool export = 1;
|
||||
|
||||
// Should the export be exact. Exact export maintains cluster-specific fields like 'Namespace'.
|
||||
optional bool exact = 2;
|
||||
}
|
||||
|
||||
// GetOptions is the standard query options to the standard REST get call.
|
||||
message GetOptions {
|
||||
// When specified:
|
||||
// - if unset, then the result is returned from remote storage based on quorum-read flag;
|
||||
// - if it's 0, then we simply return what we currently have in cache, no guarantee;
|
||||
// - if set to non zero, then the result is at least as fresh as given rv.
|
||||
optional string resourceVersion = 1;
|
||||
|
||||
// If true, partially initialized resources are included in the response.
|
||||
// +optional
|
||||
optional bool includeUninitialized = 2;
|
||||
}
|
||||
|
||||
// GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying
|
||||
// concepts during lookup stages without having partially valid types
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
message GroupKind {
|
||||
optional string group = 1;
|
||||
|
||||
optional string kind = 2;
|
||||
}
|
||||
|
||||
// GroupResource specifies a Group and a Resource, but does not force a version. This is useful for identifying
|
||||
// concepts during lookup stages without having partially valid types
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
message GroupResource {
|
||||
optional string group = 1;
|
||||
|
||||
optional string resource = 2;
|
||||
}
|
||||
|
||||
// GroupVersion contains the "group" and the "version", which uniquely identifies the API.
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
message GroupVersion {
|
||||
optional string group = 1;
|
||||
|
||||
optional string version = 2;
|
||||
}
|
||||
|
||||
// GroupVersion contains the "group/version" and "version" string of a version.
|
||||
// It is made a struct to keep extensibility.
|
||||
message GroupVersionForDiscovery {
|
||||
// groupVersion specifies the API group and version in the form "group/version"
|
||||
optional string groupVersion = 1;
|
||||
|
||||
// version specifies the version in the form of "version". This is to save
|
||||
// the clients the trouble of splitting the GroupVersion.
|
||||
optional string version = 2;
|
||||
}
|
||||
|
||||
// GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion
|
||||
// to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
message GroupVersionKind {
|
||||
optional string group = 1;
|
||||
|
||||
optional string version = 2;
|
||||
|
||||
optional string kind = 3;
|
||||
}
|
||||
|
||||
// GroupVersionResource unambiguously identifies a resource. It doesn't anonymously include GroupVersion
|
||||
// to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
message GroupVersionResource {
|
||||
optional string group = 1;
|
||||
|
||||
optional string version = 2;
|
||||
|
||||
optional string resource = 3;
|
||||
}
|
||||
|
||||
// Initializer is information about an initializer that has not yet completed.
|
||||
message Initializer {
|
||||
// name of the process that is responsible for initializing this object.
|
||||
optional string name = 1;
|
||||
}
|
||||
|
||||
// Initializers tracks the progress of initialization.
|
||||
message Initializers {
|
||||
// Pending is a list of initializers that must execute in order before this object is visible.
|
||||
// When the last pending initializer is removed, and no failing result is set, the initializers
|
||||
// struct will be set to nil and the object is considered as initialized and visible to all
|
||||
// clients.
|
||||
// +patchMergeKey=name
|
||||
// +patchStrategy=merge
|
||||
repeated Initializer pending = 1;
|
||||
|
||||
// If result is set with the Failure field, the object will be persisted to storage and then deleted,
|
||||
// ensuring that other clients can observe the deletion.
|
||||
optional Status result = 2;
|
||||
}
|
||||
|
||||
// A label selector is a label query over a set of resources. The result of matchLabels and
|
||||
// matchExpressions are ANDed. An empty label selector matches all objects. A null
|
||||
// label selector matches no objects.
|
||||
message LabelSelector {
|
||||
// matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
|
||||
// map is equivalent to an element of matchExpressions, whose key field is "key", the
|
||||
// operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||
// +optional
|
||||
map<string, string> matchLabels = 1;
|
||||
|
||||
// matchExpressions is a list of label selector requirements. The requirements are ANDed.
|
||||
// +optional
|
||||
repeated LabelSelectorRequirement matchExpressions = 2;
|
||||
}
|
||||
|
||||
// A label selector requirement is a selector that contains values, a key, and an operator that
|
||||
// relates the key and values.
|
||||
message LabelSelectorRequirement {
|
||||
// key is the label key that the selector applies to.
|
||||
// +patchMergeKey=key
|
||||
// +patchStrategy=merge
|
||||
optional string key = 1;
|
||||
|
||||
// operator represents a key's relationship to a set of values.
|
||||
// Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||
optional string operator = 2;
|
||||
|
||||
// values is an array of string values. If the operator is In or NotIn,
|
||||
// the values array must be non-empty. If the operator is Exists or DoesNotExist,
|
||||
// the values array must be empty. This array is replaced during a strategic
|
||||
// merge patch.
|
||||
// +optional
|
||||
repeated string values = 3;
|
||||
}
|
||||
|
||||
// List holds a list of objects, which may not be known by the server.
|
||||
message List {
|
||||
// Standard list metadata.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
|
||||
// +optional
|
||||
optional ListMeta metadata = 1;
|
||||
|
||||
// List of objects
|
||||
repeated k8s.io.apimachinery.pkg.runtime.RawExtension items = 2;
|
||||
}
|
||||
|
||||
// ListMeta describes metadata that synthetic resources must have, including lists and
|
||||
// various status objects. A resource may have only one of {ObjectMeta, ListMeta}.
|
||||
message ListMeta {
|
||||
// selfLink is a URL representing this object.
|
||||
// Populated by the system.
|
||||
// Read-only.
|
||||
// +optional
|
||||
optional string selfLink = 1;
|
||||
|
||||
// String that identifies the server's internal version of this object that
|
||||
// can be used by clients to determine when objects have changed.
|
||||
// Value must be treated as opaque by clients and passed unmodified back to the server.
|
||||
// Populated by the system.
|
||||
// Read-only.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency
|
||||
// +optional
|
||||
optional string resourceVersion = 2;
|
||||
|
||||
// continue may be set if the user set a limit on the number of items returned, and indicates that
|
||||
// the server has more data available. The value is opaque and may be used to issue another request
|
||||
// to the endpoint that served this list to retrieve the next set of available objects. Continuing a
|
||||
// list may not be possible if the server configuration has changed or more than a few minutes have
|
||||
// passed. The resourceVersion field returned when using this continue value will be identical to
|
||||
// the value in the first response.
|
||||
optional string continue = 3;
|
||||
}
|
||||
|
||||
// ListOptions is the query options to a standard REST list call.
|
||||
message ListOptions {
|
||||
// A selector to restrict the list of returned objects by their labels.
|
||||
// Defaults to everything.
|
||||
// +optional
|
||||
optional string labelSelector = 1;
|
||||
|
||||
// A selector to restrict the list of returned objects by their fields.
|
||||
// Defaults to everything.
|
||||
// +optional
|
||||
optional string fieldSelector = 2;
|
||||
|
||||
// If true, partially initialized resources are included in the response.
|
||||
// +optional
|
||||
optional bool includeUninitialized = 6;
|
||||
|
||||
// Watch for changes to the described resources and return them as a stream of
|
||||
// add, update, and remove notifications. Specify resourceVersion.
|
||||
// +optional
|
||||
optional bool watch = 3;
|
||||
|
||||
// When specified with a watch call, shows changes that occur after that particular version of a resource.
|
||||
// Defaults to changes from the beginning of history.
|
||||
// When specified for list:
|
||||
// - if unset, then the result is returned from remote storage based on quorum-read flag;
|
||||
// - if it's 0, then we simply return what we currently have in cache, no guarantee;
|
||||
// - if set to non zero, then the result is at least as fresh as given rv.
|
||||
// +optional
|
||||
optional string resourceVersion = 4;
|
||||
|
||||
// Timeout for the list/watch call.
|
||||
// +optional
|
||||
optional int64 timeoutSeconds = 5;
|
||||
|
||||
// limit is a maximum number of responses to return for a list call. If more items exist, the
|
||||
// server will set the `continue` field on the list metadata to a value that can be used with the
|
||||
// same initial query to retrieve the next set of results. Setting a limit may return fewer than
|
||||
// the requested amount of items (up to zero items) in the event all requested objects are
|
||||
// filtered out and clients should only use the presence of the continue field to determine whether
|
||||
// more results are available. Servers may choose not to support the limit argument and will return
|
||||
// all of the available results. If limit is specified and the continue field is empty, clients may
|
||||
// assume that no more results are available. This field is not supported if watch is true.
|
||||
//
|
||||
// The server guarantees that the objects returned when using continue will be identical to issuing
|
||||
// a single list call without a limit - that is, no objects created, modified, or deleted after the
|
||||
// first request is issued will be included in any subsequent continued requests. This is sometimes
|
||||
// referred to as a consistent snapshot, and ensures that a client that is using limit to receive
|
||||
// smaller chunks of a very large result can ensure they see all possible objects. If objects are
|
||||
// updated during a chunked list the version of the object that was present at the time the first list
|
||||
// result was calculated is returned.
|
||||
optional int64 limit = 7;
|
||||
|
||||
// The continue option should be set when retrieving more results from the server. Since this value
|
||||
// is server defined, clients may only use the continue value from a previous query result with
|
||||
// identical query parameters (except for the value of continue) and the server may reject a continue
|
||||
// value it does not recognize. If the specified continue value is no longer valid whether due to
|
||||
// expiration (generally five to fifteen minutes) or a configuration change on the server the server
|
||||
// will respond with a 410 ResourceExpired error indicating the client must restart their list without
|
||||
// the continue field. This field is not supported when watch is true. Clients may start a watch from
|
||||
// the last resourceVersion value returned by the server and not miss any modifications.
|
||||
optional string continue = 8;
|
||||
}
|
||||
|
||||
// MicroTime is version of Time with microsecond level precision.
|
||||
//
|
||||
// +protobuf.options.marshal=false
|
||||
// +protobuf.as=Timestamp
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
message MicroTime {
|
||||
// Represents seconds of UTC time since Unix epoch
|
||||
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
||||
// 9999-12-31T23:59:59Z inclusive.
|
||||
optional int64 seconds = 1;
|
||||
|
||||
// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||
// second values with fractions must still have non-negative nanos values
|
||||
// that count forward in time. Must be from 0 to 999,999,999
|
||||
// inclusive. This field may be limited in precision depending on context.
|
||||
optional int32 nanos = 2;
|
||||
}
|
||||
|
||||
// ObjectMeta is metadata that all persisted resources must have, which includes all objects
|
||||
// users must create.
|
||||
message ObjectMeta {
|
||||
// Name must be unique within a namespace. Is required when creating resources, although
|
||||
// some resources may allow a client to request the generation of an appropriate name
|
||||
// automatically. Name is primarily intended for creation idempotence and configuration
|
||||
// definition.
|
||||
// Cannot be updated.
|
||||
// More info: http://kubernetes.io/docs/user-guide/identifiers#names
|
||||
// +optional
|
||||
optional string name = 1;
|
||||
|
||||
// GenerateName is an optional prefix, used by the server, to generate a unique
|
||||
// name ONLY IF the Name field has not been provided.
|
||||
// If this field is used, the name returned to the client will be different
|
||||
// than the name passed. This value will also be combined with a unique suffix.
|
||||
// The provided value has the same validation rules as the Name field,
|
||||
// and may be truncated by the length of the suffix required to make the value
|
||||
// unique on the server.
|
||||
//
|
||||
// If this field is specified and the generated name exists, the server will
|
||||
// NOT return a 409 - instead, it will either return 201 Created or 500 with Reason
|
||||
// ServerTimeout indicating a unique name could not be found in the time allotted, and the client
|
||||
// should retry (optionally after the time indicated in the Retry-After header).
|
||||
//
|
||||
// Applied only if Name is not specified.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#idempotency
|
||||
// +optional
|
||||
optional string generateName = 2;
|
||||
|
||||
// Namespace defines the space within each name must be unique. An empty namespace is
|
||||
// equivalent to the "default" namespace, but "default" is the canonical representation.
|
||||
// Not all objects are required to be scoped to a namespace - the value of this field for
|
||||
// those objects will be empty.
|
||||
//
|
||||
// Must be a DNS_LABEL.
|
||||
// Cannot be updated.
|
||||
// More info: http://kubernetes.io/docs/user-guide/namespaces
|
||||
// +optional
|
||||
optional string namespace = 3;
|
||||
|
||||
// SelfLink is a URL representing this object.
|
||||
// Populated by the system.
|
||||
// Read-only.
|
||||
// +optional
|
||||
optional string selfLink = 4;
|
||||
|
||||
// UID is the unique in time and space value for this object. It is typically generated by
|
||||
// the server on successful creation of a resource and is not allowed to change on PUT
|
||||
// operations.
|
||||
//
|
||||
// Populated by the system.
|
||||
// Read-only.
|
||||
// More info: http://kubernetes.io/docs/user-guide/identifiers#uids
|
||||
// +optional
|
||||
optional string uid = 5;
|
||||
|
||||
// An opaque value that represents the internal version of this object that can
|
||||
// be used by clients to determine when objects have changed. May be used for optimistic
|
||||
// concurrency, change detection, and the watch operation on a resource or set of resources.
|
||||
// Clients must treat these values as opaque and passed unmodified back to the server.
|
||||
// They may only be valid for a particular resource or set of resources.
|
||||
//
|
||||
// Populated by the system.
|
||||
// Read-only.
|
||||
// Value must be treated as opaque by clients and .
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#concurrency-control-and-consistency
|
||||
// +optional
|
||||
optional string resourceVersion = 6;
|
||||
|
||||
// A sequence number representing a specific generation of the desired state.
|
||||
// Populated by the system. Read-only.
|
||||
// +optional
|
||||
optional int64 generation = 7;
|
||||
|
||||
// CreationTimestamp is a timestamp representing the server time when this object was
|
||||
// created. It is not guaranteed to be set in happens-before order across separate operations.
|
||||
// Clients may not set this value. It is represented in RFC3339 form and is in UTC.
|
||||
//
|
||||
// Populated by the system.
|
||||
// Read-only.
|
||||
// Null for lists.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
|
||||
// +optional
|
||||
optional Time creationTimestamp = 8;
|
||||
|
||||
// DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This
|
||||
// field is set by the server when a graceful deletion is requested by the user, and is not
|
||||
// directly settable by a client. The resource is expected to be deleted (no longer visible
|
||||
// from resource lists, and not reachable by name) after the time in this field, once the
|
||||
// finalizers list is empty. As long as the finalizers list contains items, deletion is blocked.
|
||||
// Once the deletionTimestamp is set, this value may not be unset or be set further into the
|
||||
// future, although it may be shortened or the resource may be deleted prior to this time.
|
||||
// For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react
|
||||
// by sending a graceful termination signal to the containers in the pod. After that 30 seconds,
|
||||
// the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,
|
||||
// remove the pod from the API. In the presence of network partitions, this object may still
|
||||
// exist after this timestamp, until an administrator or automated process can determine the
|
||||
// resource is fully terminated.
|
||||
// If not set, graceful deletion of the object has not been requested.
|
||||
//
|
||||
// Populated by the system when a graceful deletion is requested.
|
||||
// Read-only.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
|
||||
// +optional
|
||||
optional Time deletionTimestamp = 9;
|
||||
|
||||
// Number of seconds allowed for this object to gracefully terminate before
|
||||
// it will be removed from the system. Only set when deletionTimestamp is also set.
|
||||
// May only be shortened.
|
||||
// Read-only.
|
||||
// +optional
|
||||
optional int64 deletionGracePeriodSeconds = 10;
|
||||
|
||||
// Map of string keys and values that can be used to organize and categorize
|
||||
// (scope and select) objects. May match selectors of replication controllers
|
||||
// and services.
|
||||
// More info: http://kubernetes.io/docs/user-guide/labels
|
||||
// +optional
|
||||
map<string, string> labels = 11;
|
||||
|
||||
// Annotations is an unstructured key value map stored with a resource that may be
|
||||
// set by external tools to store and retrieve arbitrary metadata. They are not
|
||||
// queryable and should be preserved when modifying objects.
|
||||
// More info: http://kubernetes.io/docs/user-guide/annotations
|
||||
// +optional
|
||||
map<string, string> annotations = 12;
|
||||
|
||||
// List of objects depended by this object. If ALL objects in the list have
|
||||
// been deleted, this object will be garbage collected. If this object is managed by a controller,
|
||||
// then an entry in this list will point to this controller, with the controller field set to true.
|
||||
// There cannot be more than one managing controller.
|
||||
// +optional
|
||||
// +patchMergeKey=uid
|
||||
// +patchStrategy=merge
|
||||
repeated OwnerReference ownerReferences = 13;
|
||||
|
||||
// An initializer is a controller which enforces some system invariant at object creation time.
|
||||
// This field is a list of initializers that have not yet acted on this object. If nil or empty,
|
||||
// this object has been completely initialized. Otherwise, the object is considered uninitialized
|
||||
// and is hidden (in list/watch and get calls) from clients that haven't explicitly asked to
|
||||
// observe uninitialized objects.
|
||||
//
|
||||
// When an object is created, the system will populate this list with the current set of initializers.
|
||||
// Only privileged users may set or modify this list. Once it is empty, it may not be modified further
|
||||
// by any user.
|
||||
optional Initializers initializers = 16;
|
||||
|
||||
// Must be empty before the object is deleted from the registry. Each entry
|
||||
// is an identifier for the responsible component that will remove the entry
|
||||
// from the list. If the deletionTimestamp of the object is non-nil, entries
|
||||
// in this list can only be removed.
|
||||
// +optional
|
||||
// +patchStrategy=merge
|
||||
repeated string finalizers = 14;
|
||||
|
||||
// The name of the cluster which the object belongs to.
|
||||
// This is used to distinguish resources with same name and namespace in different clusters.
|
||||
// This field is not set anywhere right now and apiserver is going to ignore it if set in create or update request.
|
||||
// +optional
|
||||
optional string clusterName = 15;
|
||||
}
|
||||
|
||||
// OwnerReference contains enough information to let you identify an owning
|
||||
// object. Currently, an owning object must be in the same namespace, so there
|
||||
// is no namespace field.
|
||||
message OwnerReference {
|
||||
// API version of the referent.
|
||||
optional string apiVersion = 5;
|
||||
|
||||
// Kind of the referent.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
|
||||
optional string kind = 1;
|
||||
|
||||
// Name of the referent.
|
||||
// More info: http://kubernetes.io/docs/user-guide/identifiers#names
|
||||
optional string name = 3;
|
||||
|
||||
// UID of the referent.
|
||||
// More info: http://kubernetes.io/docs/user-guide/identifiers#uids
|
||||
optional string uid = 4;
|
||||
|
||||
// If true, this reference points to the managing controller.
|
||||
// +optional
|
||||
optional bool controller = 6;
|
||||
|
||||
// If true, AND if the owner has the "foregroundDeletion" finalizer, then
|
||||
// the owner cannot be deleted from the key-value store until this
|
||||
// reference is removed.
|
||||
// Defaults to false.
|
||||
// To set this field, a user needs "delete" permission of the owner,
|
||||
// otherwise 422 (Unprocessable Entity) will be returned.
|
||||
// +optional
|
||||
optional bool blockOwnerDeletion = 7;
|
||||
}
|
||||
|
||||
// Patch is provided to give a concrete name and type to the Kubernetes PATCH request body.
|
||||
message Patch {
|
||||
}
|
||||
|
||||
// Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out.
|
||||
message Preconditions {
|
||||
// Specifies the target UID.
|
||||
// +optional
|
||||
optional string uid = 1;
|
||||
}
|
||||
|
||||
// RootPaths lists the paths available at root.
|
||||
// For example: "/healthz", "/apis".
|
||||
message RootPaths {
|
||||
// paths are the paths available at root.
|
||||
repeated string paths = 1;
|
||||
}
|
||||
|
||||
// ServerAddressByClientCIDR helps the client to determine the server address that they should use, depending on the clientCIDR that they match.
|
||||
message ServerAddressByClientCIDR {
|
||||
// The CIDR with which clients can match their IP to figure out the server address that they should use.
|
||||
optional string clientCIDR = 1;
|
||||
|
||||
// Address of this server, suitable for a client that matches the above CIDR.
|
||||
// This can be a hostname, hostname:port, IP or IP:port.
|
||||
optional string serverAddress = 2;
|
||||
}
|
||||
|
||||
// Status is a return value for calls that don't return other objects.
|
||||
message Status {
|
||||
// Standard list metadata.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
|
||||
// +optional
|
||||
optional ListMeta metadata = 1;
|
||||
|
||||
// Status of the operation.
|
||||
// One of: "Success" or "Failure".
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
|
||||
// +optional
|
||||
optional string status = 2;
|
||||
|
||||
// A human-readable description of the status of this operation.
|
||||
// +optional
|
||||
optional string message = 3;
|
||||
|
||||
// A machine-readable description of why this operation is in the
|
||||
// "Failure" status. If this value is empty there
|
||||
// is no information available. A Reason clarifies an HTTP status
|
||||
// code but does not override it.
|
||||
// +optional
|
||||
optional string reason = 4;
|
||||
|
||||
// Extended data associated with the reason. Each reason may define its
|
||||
// own extended details. This field is optional and the data returned
|
||||
// is not guaranteed to conform to any schema except that defined by
|
||||
// the reason type.
|
||||
// +optional
|
||||
optional StatusDetails details = 5;
|
||||
|
||||
// Suggested HTTP return code for this status, 0 if not set.
|
||||
// +optional
|
||||
optional int32 code = 6;
|
||||
}
|
||||
|
||||
// StatusCause provides more information about an api.Status failure, including
|
||||
// cases when multiple errors are encountered.
|
||||
message StatusCause {
|
||||
// A machine-readable description of the cause of the error. If this value is
|
||||
// empty there is no information available.
|
||||
// +optional
|
||||
optional string reason = 1;
|
||||
|
||||
// A human-readable description of the cause of the error. This field may be
|
||||
// presented as-is to a reader.
|
||||
// +optional
|
||||
optional string message = 2;
|
||||
|
||||
// The field of the resource that has caused this error, as named by its JSON
|
||||
// serialization. May include dot and postfix notation for nested attributes.
|
||||
// Arrays are zero-indexed. Fields may appear more than once in an array of
|
||||
// causes due to fields having multiple errors.
|
||||
// Optional.
|
||||
//
|
||||
// Examples:
|
||||
// "name" - the field "name" on the current resource
|
||||
// "items[0].name" - the field "name" on the first array entry in "items"
|
||||
// +optional
|
||||
optional string field = 3;
|
||||
}
|
||||
|
||||
// StatusDetails is a set of additional properties that MAY be set by the
|
||||
// server to provide additional information about a response. The Reason
|
||||
// field of a Status object defines what attributes will be set. Clients
|
||||
// must ignore fields that do not match the defined type of each attribute,
|
||||
// and should assume that any attribute may be empty, invalid, or under
|
||||
// defined.
|
||||
message StatusDetails {
|
||||
// The name attribute of the resource associated with the status StatusReason
|
||||
// (when there is a single name which can be described).
|
||||
// +optional
|
||||
optional string name = 1;
|
||||
|
||||
// The group attribute of the resource associated with the status StatusReason.
|
||||
// +optional
|
||||
optional string group = 2;
|
||||
|
||||
// The kind attribute of the resource associated with the status StatusReason.
|
||||
// On some operations may differ from the requested resource Kind.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
|
||||
// +optional
|
||||
optional string kind = 3;
|
||||
|
||||
// UID of the resource.
|
||||
// (when there is a single resource which can be described).
|
||||
// More info: http://kubernetes.io/docs/user-guide/identifiers#uids
|
||||
// +optional
|
||||
optional string uid = 6;
|
||||
|
||||
// The Causes array includes more details associated with the StatusReason
|
||||
// failure. Not all StatusReasons may provide detailed causes.
|
||||
// +optional
|
||||
repeated StatusCause causes = 4;
|
||||
|
||||
// If specified, the time in seconds before the operation should be retried. Some errors may indicate
|
||||
// the client must take an alternate action - for those errors this field may indicate how long to wait
|
||||
// before taking the alternate action.
|
||||
// +optional
|
||||
optional int32 retryAfterSeconds = 5;
|
||||
}
|
||||
|
||||
// Time is a wrapper around time.Time which supports correct
|
||||
// marshaling to YAML and JSON. Wrappers are provided for many
|
||||
// of the factory methods that the time package offers.
|
||||
//
|
||||
// +protobuf.options.marshal=false
|
||||
// +protobuf.as=Timestamp
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
message Time {
|
||||
// Represents seconds of UTC time since Unix epoch
|
||||
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
||||
// 9999-12-31T23:59:59Z inclusive.
|
||||
optional int64 seconds = 1;
|
||||
|
||||
// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||
// second values with fractions must still have non-negative nanos values
|
||||
// that count forward in time. Must be from 0 to 999,999,999
|
||||
// inclusive. This field may be limited in precision depending on context.
|
||||
optional int32 nanos = 2;
|
||||
}
|
||||
|
||||
// Timestamp is a struct that is equivalent to Time, but intended for
|
||||
// protobuf marshalling/unmarshalling. It is generated into a serialization
|
||||
// that matches Time. Do not use in Go structs.
|
||||
message Timestamp {
|
||||
// Represents seconds of UTC time since Unix epoch
|
||||
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
||||
// 9999-12-31T23:59:59Z inclusive.
|
||||
optional int64 seconds = 1;
|
||||
|
||||
// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||
// second values with fractions must still have non-negative nanos values
|
||||
// that count forward in time. Must be from 0 to 999,999,999
|
||||
// inclusive. This field may be limited in precision depending on context.
|
||||
optional int32 nanos = 2;
|
||||
}
|
||||
|
||||
// TypeMeta describes an individual object in an API response or request
|
||||
// with strings representing the type of the object and its API schema version.
|
||||
// Structures that are versioned or persisted should inline TypeMeta.
|
||||
//
|
||||
// +k8s:deepcopy-gen=false
|
||||
message TypeMeta {
|
||||
// Kind is a string value representing the REST resource this object represents.
|
||||
// Servers may infer this from the endpoint the client submits requests to.
|
||||
// Cannot be updated.
|
||||
// In CamelCase.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
|
||||
// +optional
|
||||
optional string kind = 1;
|
||||
|
||||
// APIVersion defines the versioned schema of this representation of an object.
|
||||
// Servers should convert recognized schemas to the latest internal value, and
|
||||
// may reject unrecognized values.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources
|
||||
// +optional
|
||||
optional string apiVersion = 2;
|
||||
}
|
||||
|
||||
// Verbs masks the value so protobuf can generate
|
||||
//
|
||||
// +protobuf.nullable=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
message Verbs {
|
||||
// items, if empty, will result in an empty slice
|
||||
|
||||
repeated string items = 1;
|
||||
}
|
||||
|
||||
// Event represents a single event to a watched resource.
|
||||
//
|
||||
// +protobuf=true
|
||||
// +k8s:deepcopy-gen=true
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
message WatchEvent {
|
||||
optional string type = 1;
|
||||
|
||||
// Object is:
|
||||
// * If Type is Added or Modified: the new state of the object.
|
||||
// * If Type is Deleted: the state of the object immediately before deletion.
|
||||
// * If Type is Error: *Status is recommended; other types may make sense
|
||||
// depending on context.
|
||||
optional k8s.io.apimachinery.pkg.runtime.RawExtension object = 2;
|
||||
}
|
||||
|
148
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/group_version.go
generated
vendored
Normal file
148
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/group_version.go
generated
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
Copyright 2015 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"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// GroupResource specifies a Group and a Resource, but does not force a version. This is useful for identifying
|
||||
// concepts during lookup stages without having partially valid types
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type GroupResource struct {
|
||||
Group string `json:"group" protobuf:"bytes,1,opt,name=group"`
|
||||
Resource string `json:"resource" protobuf:"bytes,2,opt,name=resource"`
|
||||
}
|
||||
|
||||
func (gr *GroupResource) String() string {
|
||||
if len(gr.Group) == 0 {
|
||||
return gr.Resource
|
||||
}
|
||||
return gr.Resource + "." + gr.Group
|
||||
}
|
||||
|
||||
// GroupVersionResource unambiguously identifies a resource. It doesn't anonymously include GroupVersion
|
||||
// to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type GroupVersionResource struct {
|
||||
Group string `json:"group" protobuf:"bytes,1,opt,name=group"`
|
||||
Version string `json:"version" protobuf:"bytes,2,opt,name=version"`
|
||||
Resource string `json:"resource" protobuf:"bytes,3,opt,name=resource"`
|
||||
}
|
||||
|
||||
func (gvr *GroupVersionResource) String() string {
|
||||
return strings.Join([]string{gvr.Group, "/", gvr.Version, ", Resource=", gvr.Resource}, "")
|
||||
}
|
||||
|
||||
// GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying
|
||||
// concepts during lookup stages without having partially valid types
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type GroupKind struct {
|
||||
Group string `json:"group" protobuf:"bytes,1,opt,name=group"`
|
||||
Kind string `json:"kind" protobuf:"bytes,2,opt,name=kind"`
|
||||
}
|
||||
|
||||
func (gk *GroupKind) String() string {
|
||||
if len(gk.Group) == 0 {
|
||||
return gk.Kind
|
||||
}
|
||||
return gk.Kind + "." + gk.Group
|
||||
}
|
||||
|
||||
// GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion
|
||||
// to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type GroupVersionKind struct {
|
||||
Group string `json:"group" protobuf:"bytes,1,opt,name=group"`
|
||||
Version string `json:"version" protobuf:"bytes,2,opt,name=version"`
|
||||
Kind string `json:"kind" protobuf:"bytes,3,opt,name=kind"`
|
||||
}
|
||||
|
||||
func (gvk GroupVersionKind) String() string {
|
||||
return gvk.Group + "/" + gvk.Version + ", Kind=" + gvk.Kind
|
||||
}
|
||||
|
||||
// GroupVersion contains the "group" and the "version", which uniquely identifies the API.
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type GroupVersion struct {
|
||||
Group string `json:"group" protobuf:"bytes,1,opt,name=group"`
|
||||
Version string `json:"version" protobuf:"bytes,2,opt,name=version"`
|
||||
}
|
||||
|
||||
// Empty returns true if group and version are empty
|
||||
func (gv GroupVersion) Empty() bool {
|
||||
return len(gv.Group) == 0 && len(gv.Version) == 0
|
||||
}
|
||||
|
||||
// String puts "group" and "version" into a single "group/version" string. For the legacy v1
|
||||
// it returns "v1".
|
||||
func (gv GroupVersion) String() string {
|
||||
// special case the internal apiVersion for the legacy kube types
|
||||
if gv.Empty() {
|
||||
return ""
|
||||
}
|
||||
|
||||
// special case of "v1" for backward compatibility
|
||||
if len(gv.Group) == 0 && gv.Version == "v1" {
|
||||
return gv.Version
|
||||
}
|
||||
if len(gv.Group) > 0 {
|
||||
return gv.Group + "/" + gv.Version
|
||||
}
|
||||
return gv.Version
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaller interface.
|
||||
func (gv GroupVersion) MarshalJSON() ([]byte, error) {
|
||||
s := gv.String()
|
||||
if strings.Count(s, "/") > 1 {
|
||||
return []byte{}, fmt.Errorf("illegal GroupVersion %v: contains more than one /", s)
|
||||
}
|
||||
return json.Marshal(s)
|
||||
}
|
||||
|
||||
func (gv *GroupVersion) unmarshal(value []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(value, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
parsed, err := schema.ParseGroupVersion(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gv.Group, gv.Version = parsed.Group, parsed.Version
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaller interface.
|
||||
func (gv *GroupVersion) UnmarshalJSON(value []byte) error {
|
||||
return gv.unmarshal(value)
|
||||
}
|
||||
|
||||
// UnmarshalTEXT implements the Ugorji's encoding.TextUnmarshaler interface.
|
||||
func (gv *GroupVersion) UnmarshalText(value []byte) error {
|
||||
return gv.unmarshal(value)
|
||||
}
|
78
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/group_version_test.go
generated
vendored
Normal file
78
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/group_version_test.go
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2015 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"
|
||||
"testing"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
type GroupVersionHolder struct {
|
||||
GV GroupVersion `json:"val"`
|
||||
}
|
||||
|
||||
func TestGroupVersionUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input []byte
|
||||
expect GroupVersion
|
||||
}{
|
||||
{[]byte(`{"val": "v1"}`), GroupVersion{"", "v1"}},
|
||||
{[]byte(`{"val": "extensions/v1beta1"}`), GroupVersion{"extensions", "v1beta1"}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result GroupVersionHolder
|
||||
// test golang lib's JSON codec
|
||||
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("JSON codec failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(result.GV, c.expect) {
|
||||
t.Errorf("JSON codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV)
|
||||
}
|
||||
// test the json-iterator codec
|
||||
if err := jsoniter.ConfigFastest.Unmarshal(c.input, &result); err != nil {
|
||||
t.Errorf("json-iterator codec failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(result.GV, c.expect) {
|
||||
t.Errorf("json-iterator codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupVersionMarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input GroupVersion
|
||||
expect []byte
|
||||
}{
|
||||
{GroupVersion{"", "v1"}, []byte(`{"val":"v1"}`)},
|
||||
{GroupVersion{"extensions", "v1beta1"}, []byte(`{"val":"extensions/v1beta1"}`)},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := GroupVersionHolder{c.input}
|
||||
result, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal input '%v': %v", input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(result, c.expect) {
|
||||
t.Errorf("Failed to marshal input '%+v': expected: %s, got: %s", input, c.expect, result)
|
||||
}
|
||||
}
|
||||
}
|
234
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/helpers.go
generated
vendored
Normal file
234
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/helpers.go
generated
vendored
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
Copyright 2016 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 (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// LabelSelectorAsSelector converts the LabelSelector api type into a struct that implements
|
||||
// labels.Selector
|
||||
// Note: This function should be kept in sync with the selector methods in pkg/labels/selector.go
|
||||
func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) {
|
||||
if ps == nil {
|
||||
return labels.Nothing(), nil
|
||||
}
|
||||
if len(ps.MatchLabels)+len(ps.MatchExpressions) == 0 {
|
||||
return labels.Everything(), nil
|
||||
}
|
||||
selector := labels.NewSelector()
|
||||
for k, v := range ps.MatchLabels {
|
||||
r, err := labels.NewRequirement(k, selection.Equals, []string{v})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selector = selector.Add(*r)
|
||||
}
|
||||
for _, expr := range ps.MatchExpressions {
|
||||
var op selection.Operator
|
||||
switch expr.Operator {
|
||||
case LabelSelectorOpIn:
|
||||
op = selection.In
|
||||
case LabelSelectorOpNotIn:
|
||||
op = selection.NotIn
|
||||
case LabelSelectorOpExists:
|
||||
op = selection.Exists
|
||||
case LabelSelectorOpDoesNotExist:
|
||||
op = selection.DoesNotExist
|
||||
default:
|
||||
return nil, fmt.Errorf("%q is not a valid pod selector operator", expr.Operator)
|
||||
}
|
||||
r, err := labels.NewRequirement(expr.Key, op, append([]string(nil), expr.Values...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selector = selector.Add(*r)
|
||||
}
|
||||
return selector, nil
|
||||
}
|
||||
|
||||
// LabelSelectorAsMap converts the LabelSelector api type into a map of strings, ie. the
|
||||
// original structure of a label selector. Operators that cannot be converted into plain
|
||||
// labels (Exists, DoesNotExist, NotIn, and In with more than one value) will result in
|
||||
// an error.
|
||||
func LabelSelectorAsMap(ps *LabelSelector) (map[string]string, error) {
|
||||
if ps == nil {
|
||||
return nil, nil
|
||||
}
|
||||
selector := map[string]string{}
|
||||
for k, v := range ps.MatchLabels {
|
||||
selector[k] = v
|
||||
}
|
||||
for _, expr := range ps.MatchExpressions {
|
||||
switch expr.Operator {
|
||||
case LabelSelectorOpIn:
|
||||
if len(expr.Values) != 1 {
|
||||
return selector, fmt.Errorf("operator %q without a single value cannot be converted into the old label selector format", expr.Operator)
|
||||
}
|
||||
// Should we do anything in case this will override a previous key-value pair?
|
||||
selector[expr.Key] = expr.Values[0]
|
||||
case LabelSelectorOpNotIn, LabelSelectorOpExists, LabelSelectorOpDoesNotExist:
|
||||
return selector, fmt.Errorf("operator %q cannot be converted into the old label selector format", expr.Operator)
|
||||
default:
|
||||
return selector, fmt.Errorf("%q is not a valid selector operator", expr.Operator)
|
||||
}
|
||||
}
|
||||
return selector, nil
|
||||
}
|
||||
|
||||
// ParseToLabelSelector parses a string representing a selector into a LabelSelector object.
|
||||
// Note: This function should be kept in sync with the parser in pkg/labels/selector.go
|
||||
func ParseToLabelSelector(selector string) (*LabelSelector, error) {
|
||||
reqs, err := labels.ParseToRequirements(selector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't parse the selector string \"%s\": %v", selector, err)
|
||||
}
|
||||
|
||||
labelSelector := &LabelSelector{
|
||||
MatchLabels: map[string]string{},
|
||||
MatchExpressions: []LabelSelectorRequirement{},
|
||||
}
|
||||
for _, req := range reqs {
|
||||
var op LabelSelectorOperator
|
||||
switch req.Operator() {
|
||||
case selection.Equals, selection.DoubleEquals:
|
||||
vals := req.Values()
|
||||
if vals.Len() != 1 {
|
||||
return nil, fmt.Errorf("equals operator must have exactly one value")
|
||||
}
|
||||
val, ok := vals.PopAny()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("equals operator has exactly one value but it cannot be retrieved")
|
||||
}
|
||||
labelSelector.MatchLabels[req.Key()] = val
|
||||
continue
|
||||
case selection.In:
|
||||
op = LabelSelectorOpIn
|
||||
case selection.NotIn:
|
||||
op = LabelSelectorOpNotIn
|
||||
case selection.Exists:
|
||||
op = LabelSelectorOpExists
|
||||
case selection.DoesNotExist:
|
||||
op = LabelSelectorOpDoesNotExist
|
||||
case selection.GreaterThan, selection.LessThan:
|
||||
// Adding a separate case for these operators to indicate that this is deliberate
|
||||
return nil, fmt.Errorf("%q isn't supported in label selectors", req.Operator())
|
||||
default:
|
||||
return nil, fmt.Errorf("%q is not a valid label selector operator", req.Operator())
|
||||
}
|
||||
labelSelector.MatchExpressions = append(labelSelector.MatchExpressions, LabelSelectorRequirement{
|
||||
Key: req.Key(),
|
||||
Operator: op,
|
||||
Values: req.Values().List(),
|
||||
})
|
||||
}
|
||||
return labelSelector, nil
|
||||
}
|
||||
|
||||
// SetAsLabelSelector converts the labels.Set object into a LabelSelector api object.
|
||||
func SetAsLabelSelector(ls labels.Set) *LabelSelector {
|
||||
if ls == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
selector := &LabelSelector{
|
||||
MatchLabels: make(map[string]string),
|
||||
}
|
||||
for label, value := range ls {
|
||||
selector.MatchLabels[label] = value
|
||||
}
|
||||
|
||||
return selector
|
||||
}
|
||||
|
||||
// FormatLabelSelector convert labelSelector into plain string
|
||||
func FormatLabelSelector(labelSelector *LabelSelector) string {
|
||||
selector, err := LabelSelectorAsSelector(labelSelector)
|
||||
if err != nil {
|
||||
return "<error>"
|
||||
}
|
||||
|
||||
l := selector.String()
|
||||
if len(l) == 0 {
|
||||
l = "<none>"
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func ExtractGroupVersions(l *APIGroupList) []string {
|
||||
var groupVersions []string
|
||||
for _, g := range l.Groups {
|
||||
for _, gv := range g.Versions {
|
||||
groupVersions = append(groupVersions, gv.GroupVersion)
|
||||
}
|
||||
}
|
||||
return groupVersions
|
||||
}
|
||||
|
||||
// HasAnnotation returns a bool if passed in annotation exists
|
||||
func HasAnnotation(obj ObjectMeta, ann string) bool {
|
||||
_, found := obj.Annotations[ann]
|
||||
return found
|
||||
}
|
||||
|
||||
// SetMetaDataAnnotation sets the annotation and value
|
||||
func SetMetaDataAnnotation(obj *ObjectMeta, ann string, value string) {
|
||||
if obj.Annotations == nil {
|
||||
obj.Annotations = make(map[string]string)
|
||||
}
|
||||
obj.Annotations[ann] = value
|
||||
}
|
||||
|
||||
// SingleObject returns a ListOptions for watching a single object.
|
||||
func SingleObject(meta ObjectMeta) ListOptions {
|
||||
return ListOptions{
|
||||
FieldSelector: fields.OneTermEqualSelector("metadata.name", meta.Name).String(),
|
||||
ResourceVersion: meta.ResourceVersion,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDeleteOptions returns a DeleteOptions indicating the resource should
|
||||
// be deleted within the specified grace period. Use zero to indicate
|
||||
// immediate deletion. If you would prefer to use the default grace period,
|
||||
// use &metav1.DeleteOptions{} directly.
|
||||
func NewDeleteOptions(grace int64) *DeleteOptions {
|
||||
return &DeleteOptions{GracePeriodSeconds: &grace}
|
||||
}
|
||||
|
||||
// NewPreconditionDeleteOptions returns a DeleteOptions with a UID precondition set.
|
||||
func NewPreconditionDeleteOptions(uid string) *DeleteOptions {
|
||||
u := types.UID(uid)
|
||||
p := Preconditions{UID: &u}
|
||||
return &DeleteOptions{Preconditions: &p}
|
||||
}
|
||||
|
||||
// NewUIDPreconditions returns a Preconditions with UID set.
|
||||
func NewUIDPreconditions(uid string) *Preconditions {
|
||||
u := types.UID(uid)
|
||||
return &Preconditions{UID: &u}
|
||||
}
|
||||
|
||||
// HasObjectMetaSystemFieldValues returns true if fields that are managed by the system on ObjectMeta have values.
|
||||
func HasObjectMetaSystemFieldValues(meta Object) bool {
|
||||
return !meta.GetCreationTimestamp().Time.IsZero() ||
|
||||
len(meta.GetUID()) != 0
|
||||
}
|
154
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/helpers_test.go
generated
vendored
Normal file
154
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/helpers_test.go
generated
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
Copyright 2016 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 (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
func TestLabelSelectorAsSelector(t *testing.T) {
|
||||
matchLabels := map[string]string{"foo": "bar"}
|
||||
matchExpressions := []LabelSelectorRequirement{{
|
||||
Key: "baz",
|
||||
Operator: LabelSelectorOpIn,
|
||||
Values: []string{"qux", "norf"},
|
||||
}}
|
||||
mustParse := func(s string) labels.Selector {
|
||||
out, e := labels.Parse(s)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
return out
|
||||
}
|
||||
tc := []struct {
|
||||
in *LabelSelector
|
||||
out labels.Selector
|
||||
expectErr bool
|
||||
}{
|
||||
{in: nil, out: labels.Nothing()},
|
||||
{in: &LabelSelector{}, out: labels.Everything()},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels},
|
||||
out: mustParse("foo=bar"),
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchExpressions: matchExpressions},
|
||||
out: mustParse("baz in (norf,qux)"),
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions},
|
||||
out: mustParse("baz in (norf,qux),foo=bar"),
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{
|
||||
MatchExpressions: []LabelSelectorRequirement{{
|
||||
Key: "baz",
|
||||
Operator: LabelSelectorOpExists,
|
||||
Values: []string{"qux", "norf"},
|
||||
}},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tc {
|
||||
out, err := LabelSelectorAsSelector(tc.in)
|
||||
if err == nil && tc.expectErr {
|
||||
t.Errorf("[%v]expected error but got none.", i)
|
||||
}
|
||||
if err != nil && !tc.expectErr {
|
||||
t.Errorf("[%v]did not expect error but got: %v", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(out, tc.out) {
|
||||
t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLabelSelectorAsMap(t *testing.T) {
|
||||
matchLabels := map[string]string{"foo": "bar"}
|
||||
matchExpressions := func(operator LabelSelectorOperator, values []string) []LabelSelectorRequirement {
|
||||
return []LabelSelectorRequirement{{
|
||||
Key: "baz",
|
||||
Operator: operator,
|
||||
Values: values,
|
||||
}}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
in *LabelSelector
|
||||
out map[string]string
|
||||
errString string
|
||||
}{
|
||||
{in: nil, out: nil},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels},
|
||||
out: map[string]string{"foo": "bar"},
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions(LabelSelectorOpIn, []string{"norf"})},
|
||||
out: map[string]string{"foo": "bar", "baz": "norf"},
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchExpressions: matchExpressions(LabelSelectorOpIn, []string{"norf"})},
|
||||
out: map[string]string{"baz": "norf"},
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions(LabelSelectorOpIn, []string{"norf", "qux"})},
|
||||
out: map[string]string{"foo": "bar"},
|
||||
errString: "without a single value cannot be converted",
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchExpressions: matchExpressions(LabelSelectorOpNotIn, []string{"norf", "qux"})},
|
||||
out: map[string]string{},
|
||||
errString: "cannot be converted",
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions(LabelSelectorOpExists, []string{})},
|
||||
out: map[string]string{"foo": "bar"},
|
||||
errString: "cannot be converted",
|
||||
},
|
||||
{
|
||||
in: &LabelSelector{MatchExpressions: matchExpressions(LabelSelectorOpDoesNotExist, []string{})},
|
||||
out: map[string]string{},
|
||||
errString: "cannot be converted",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
out, err := LabelSelectorAsMap(tc.in)
|
||||
if err == nil && len(tc.errString) > 0 {
|
||||
t.Errorf("[%v]expected error but got none.", i)
|
||||
continue
|
||||
}
|
||||
if err != nil && len(tc.errString) == 0 {
|
||||
t.Errorf("[%v]did not expect error but got: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if err != nil && len(tc.errString) > 0 && !strings.Contains(err.Error(), tc.errString) {
|
||||
t.Errorf("[%v]expected error with %q but got: %v", i, tc.errString, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(out, tc.out) {
|
||||
t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out)
|
||||
}
|
||||
}
|
||||
}
|
75
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/labels.go
generated
vendored
Normal file
75
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/labels.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
Copyright 2016 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
|
||||
|
||||
// Clones the given selector and returns a new selector with the given key and value added.
|
||||
// Returns the given selector, if labelKey is empty.
|
||||
func CloneSelectorAndAddLabel(selector *LabelSelector, labelKey, labelValue string) *LabelSelector {
|
||||
if labelKey == "" {
|
||||
// Don't need to add a label.
|
||||
return selector
|
||||
}
|
||||
|
||||
// Clone.
|
||||
newSelector := new(LabelSelector)
|
||||
|
||||
// TODO(madhusudancs): Check if you can use deepCopy_extensions_LabelSelector here.
|
||||
newSelector.MatchLabels = make(map[string]string)
|
||||
if selector.MatchLabels != nil {
|
||||
for key, val := range selector.MatchLabels {
|
||||
newSelector.MatchLabels[key] = val
|
||||
}
|
||||
}
|
||||
newSelector.MatchLabels[labelKey] = labelValue
|
||||
|
||||
if selector.MatchExpressions != nil {
|
||||
newMExps := make([]LabelSelectorRequirement, len(selector.MatchExpressions))
|
||||
for i, me := range selector.MatchExpressions {
|
||||
newMExps[i].Key = me.Key
|
||||
newMExps[i].Operator = me.Operator
|
||||
if me.Values != nil {
|
||||
newMExps[i].Values = make([]string, len(me.Values))
|
||||
copy(newMExps[i].Values, me.Values)
|
||||
} else {
|
||||
newMExps[i].Values = nil
|
||||
}
|
||||
}
|
||||
newSelector.MatchExpressions = newMExps
|
||||
} else {
|
||||
newSelector.MatchExpressions = nil
|
||||
}
|
||||
|
||||
return newSelector
|
||||
}
|
||||
|
||||
// AddLabelToSelector returns a selector with the given key and value added to the given selector's MatchLabels.
|
||||
func AddLabelToSelector(selector *LabelSelector, labelKey, labelValue string) *LabelSelector {
|
||||
if labelKey == "" {
|
||||
// Don't need to add a label.
|
||||
return selector
|
||||
}
|
||||
if selector.MatchLabels == nil {
|
||||
selector.MatchLabels = make(map[string]string)
|
||||
}
|
||||
selector.MatchLabels[labelKey] = labelValue
|
||||
return selector
|
||||
}
|
||||
|
||||
// SelectorHasLabel checks if the given selector contains the given label key in its MatchLabels
|
||||
func SelectorHasLabel(selector *LabelSelector, labelKey string) bool {
|
||||
return len(selector.MatchLabels[labelKey]) > 0
|
||||
}
|
120
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/labels_test.go
generated
vendored
Normal file
120
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/labels_test.go
generated
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright 2016 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 (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCloneSelectorAndAddLabel(t *testing.T) {
|
||||
labels := map[string]string{
|
||||
"foo1": "bar1",
|
||||
"foo2": "bar2",
|
||||
"foo3": "bar3",
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
labels map[string]string
|
||||
labelKey string
|
||||
labelValue string
|
||||
want map[string]string
|
||||
}{
|
||||
{
|
||||
labels: labels,
|
||||
want: labels,
|
||||
},
|
||||
{
|
||||
labels: labels,
|
||||
labelKey: "foo4",
|
||||
labelValue: "89",
|
||||
want: map[string]string{
|
||||
"foo1": "bar1",
|
||||
"foo2": "bar2",
|
||||
"foo3": "bar3",
|
||||
"foo4": "89",
|
||||
},
|
||||
},
|
||||
{
|
||||
labels: nil,
|
||||
labelKey: "foo4",
|
||||
labelValue: "12",
|
||||
want: map[string]string{
|
||||
"foo4": "12",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
ls_in := LabelSelector{MatchLabels: tc.labels}
|
||||
ls_out := LabelSelector{MatchLabels: tc.want}
|
||||
|
||||
got := CloneSelectorAndAddLabel(&ls_in, tc.labelKey, tc.labelValue)
|
||||
if !reflect.DeepEqual(got, &ls_out) {
|
||||
t.Errorf("got %v, want %v", got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddLabelToSelector(t *testing.T) {
|
||||
labels := map[string]string{
|
||||
"foo1": "bar1",
|
||||
"foo2": "bar2",
|
||||
"foo3": "bar3",
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
labels map[string]string
|
||||
labelKey string
|
||||
labelValue string
|
||||
want map[string]string
|
||||
}{
|
||||
{
|
||||
labels: labels,
|
||||
want: labels,
|
||||
},
|
||||
{
|
||||
labels: labels,
|
||||
labelKey: "foo4",
|
||||
labelValue: "89",
|
||||
want: map[string]string{
|
||||
"foo1": "bar1",
|
||||
"foo2": "bar2",
|
||||
"foo3": "bar3",
|
||||
"foo4": "89",
|
||||
},
|
||||
},
|
||||
{
|
||||
labels: nil,
|
||||
labelKey: "foo4",
|
||||
labelValue: "12",
|
||||
want: map[string]string{
|
||||
"foo4": "12",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
ls_in := LabelSelector{MatchLabels: tc.labels}
|
||||
ls_out := LabelSelector{MatchLabels: tc.want}
|
||||
|
||||
got := AddLabelToSelector(&ls_in, tc.labelKey, tc.labelValue)
|
||||
if !reflect.DeepEqual(got, &ls_out) {
|
||||
t.Errorf("got %v, want %v", got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
216
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/meta.go
generated
vendored
Normal file
216
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/meta.go
generated
vendored
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
Copyright 2016 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 (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// TODO: move this, Object, List, and Type to a different package
|
||||
type ObjectMetaAccessor interface {
|
||||
GetObjectMeta() Object
|
||||
}
|
||||
|
||||
// Object lets you work with object metadata from any of the versioned or
|
||||
// internal API objects. Attempting to set or retrieve a field on an object that does
|
||||
// not support that field (Name, UID, Namespace on lists) will be a no-op and return
|
||||
// a default value.
|
||||
type Object interface {
|
||||
GetNamespace() string
|
||||
SetNamespace(namespace string)
|
||||
GetName() string
|
||||
SetName(name string)
|
||||
GetGenerateName() string
|
||||
SetGenerateName(name string)
|
||||
GetUID() types.UID
|
||||
SetUID(uid types.UID)
|
||||
GetResourceVersion() string
|
||||
SetResourceVersion(version string)
|
||||
GetGeneration() int64
|
||||
SetGeneration(generation int64)
|
||||
GetSelfLink() string
|
||||
SetSelfLink(selfLink string)
|
||||
GetCreationTimestamp() Time
|
||||
SetCreationTimestamp(timestamp Time)
|
||||
GetDeletionTimestamp() *Time
|
||||
SetDeletionTimestamp(timestamp *Time)
|
||||
GetDeletionGracePeriodSeconds() *int64
|
||||
SetDeletionGracePeriodSeconds(*int64)
|
||||
GetLabels() map[string]string
|
||||
SetLabels(labels map[string]string)
|
||||
GetAnnotations() map[string]string
|
||||
SetAnnotations(annotations map[string]string)
|
||||
GetInitializers() *Initializers
|
||||
SetInitializers(initializers *Initializers)
|
||||
GetFinalizers() []string
|
||||
SetFinalizers(finalizers []string)
|
||||
GetOwnerReferences() []OwnerReference
|
||||
SetOwnerReferences([]OwnerReference)
|
||||
GetClusterName() string
|
||||
SetClusterName(clusterName string)
|
||||
}
|
||||
|
||||
// ListMetaAccessor retrieves the list interface from an object
|
||||
type ListMetaAccessor interface {
|
||||
GetListMeta() ListInterface
|
||||
}
|
||||
|
||||
// Common lets you work with core metadata from any of the versioned or
|
||||
// internal API objects. Attempting to set or retrieve a field on an object that does
|
||||
// not support that field will be a no-op and return a default value.
|
||||
// TODO: move this, and TypeMeta and ListMeta, to a different package
|
||||
type Common interface {
|
||||
GetResourceVersion() string
|
||||
SetResourceVersion(version string)
|
||||
GetSelfLink() string
|
||||
SetSelfLink(selfLink string)
|
||||
}
|
||||
|
||||
// ListInterface lets you work with list metadata from any of the versioned or
|
||||
// internal API objects. Attempting to set or retrieve a field on an object that does
|
||||
// not support that field will be a no-op and return a default value.
|
||||
// TODO: move this, and TypeMeta and ListMeta, to a different package
|
||||
type ListInterface interface {
|
||||
GetResourceVersion() string
|
||||
SetResourceVersion(version string)
|
||||
GetSelfLink() string
|
||||
SetSelfLink(selfLink string)
|
||||
GetContinue() string
|
||||
SetContinue(c string)
|
||||
}
|
||||
|
||||
// Type exposes the type and APIVersion of versioned or internal API objects.
|
||||
// TODO: move this, and TypeMeta and ListMeta, to a different package
|
||||
type Type interface {
|
||||
GetAPIVersion() string
|
||||
SetAPIVersion(version string)
|
||||
GetKind() string
|
||||
SetKind(kind string)
|
||||
}
|
||||
|
||||
func (meta *ListMeta) GetResourceVersion() string { return meta.ResourceVersion }
|
||||
func (meta *ListMeta) SetResourceVersion(version string) { meta.ResourceVersion = version }
|
||||
func (meta *ListMeta) GetSelfLink() string { return meta.SelfLink }
|
||||
func (meta *ListMeta) SetSelfLink(selfLink string) { meta.SelfLink = selfLink }
|
||||
func (meta *ListMeta) GetContinue() string { return meta.Continue }
|
||||
func (meta *ListMeta) SetContinue(c string) { meta.Continue = c }
|
||||
|
||||
func (obj *TypeMeta) GetObjectKind() schema.ObjectKind { return obj }
|
||||
|
||||
// SetGroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta
|
||||
func (obj *TypeMeta) SetGroupVersionKind(gvk schema.GroupVersionKind) {
|
||||
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
||||
}
|
||||
|
||||
// GroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta
|
||||
func (obj *TypeMeta) GroupVersionKind() schema.GroupVersionKind {
|
||||
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
||||
}
|
||||
|
||||
func (obj *ListMeta) GetListMeta() ListInterface { return obj }
|
||||
|
||||
func (obj *ObjectMeta) GetObjectMeta() Object { return obj }
|
||||
|
||||
// Namespace implements metav1.Object for any object with an ObjectMeta typed field. Allows
|
||||
// fast, direct access to metadata fields for API objects.
|
||||
func (meta *ObjectMeta) GetNamespace() string { return meta.Namespace }
|
||||
func (meta *ObjectMeta) SetNamespace(namespace string) { meta.Namespace = namespace }
|
||||
func (meta *ObjectMeta) GetName() string { return meta.Name }
|
||||
func (meta *ObjectMeta) SetName(name string) { meta.Name = name }
|
||||
func (meta *ObjectMeta) GetGenerateName() string { return meta.GenerateName }
|
||||
func (meta *ObjectMeta) SetGenerateName(generateName string) { meta.GenerateName = generateName }
|
||||
func (meta *ObjectMeta) GetUID() types.UID { return meta.UID }
|
||||
func (meta *ObjectMeta) SetUID(uid types.UID) { meta.UID = uid }
|
||||
func (meta *ObjectMeta) GetResourceVersion() string { return meta.ResourceVersion }
|
||||
func (meta *ObjectMeta) SetResourceVersion(version string) { meta.ResourceVersion = version }
|
||||
func (meta *ObjectMeta) GetGeneration() int64 { return meta.Generation }
|
||||
func (meta *ObjectMeta) SetGeneration(generation int64) { meta.Generation = generation }
|
||||
func (meta *ObjectMeta) GetSelfLink() string { return meta.SelfLink }
|
||||
func (meta *ObjectMeta) SetSelfLink(selfLink string) { meta.SelfLink = selfLink }
|
||||
func (meta *ObjectMeta) GetCreationTimestamp() Time { return meta.CreationTimestamp }
|
||||
func (meta *ObjectMeta) SetCreationTimestamp(creationTimestamp Time) {
|
||||
meta.CreationTimestamp = creationTimestamp
|
||||
}
|
||||
func (meta *ObjectMeta) GetDeletionTimestamp() *Time { return meta.DeletionTimestamp }
|
||||
func (meta *ObjectMeta) SetDeletionTimestamp(deletionTimestamp *Time) {
|
||||
meta.DeletionTimestamp = deletionTimestamp
|
||||
}
|
||||
func (meta *ObjectMeta) GetDeletionGracePeriodSeconds() *int64 { return meta.DeletionGracePeriodSeconds }
|
||||
func (meta *ObjectMeta) SetDeletionGracePeriodSeconds(deletionGracePeriodSeconds *int64) {
|
||||
meta.DeletionGracePeriodSeconds = deletionGracePeriodSeconds
|
||||
}
|
||||
func (meta *ObjectMeta) GetLabels() map[string]string { return meta.Labels }
|
||||
func (meta *ObjectMeta) SetLabels(labels map[string]string) { meta.Labels = labels }
|
||||
func (meta *ObjectMeta) GetAnnotations() map[string]string { return meta.Annotations }
|
||||
func (meta *ObjectMeta) SetAnnotations(annotations map[string]string) { meta.Annotations = annotations }
|
||||
func (meta *ObjectMeta) GetInitializers() *Initializers { return meta.Initializers }
|
||||
func (meta *ObjectMeta) SetInitializers(initializers *Initializers) { meta.Initializers = initializers }
|
||||
func (meta *ObjectMeta) GetFinalizers() []string { return meta.Finalizers }
|
||||
func (meta *ObjectMeta) SetFinalizers(finalizers []string) { meta.Finalizers = finalizers }
|
||||
|
||||
func (meta *ObjectMeta) GetOwnerReferences() []OwnerReference {
|
||||
if meta.OwnerReferences == nil {
|
||||
return nil
|
||||
}
|
||||
ret := make([]OwnerReference, len(meta.OwnerReferences))
|
||||
for i := 0; i < len(meta.OwnerReferences); i++ {
|
||||
ret[i].Kind = meta.OwnerReferences[i].Kind
|
||||
ret[i].Name = meta.OwnerReferences[i].Name
|
||||
ret[i].UID = meta.OwnerReferences[i].UID
|
||||
ret[i].APIVersion = meta.OwnerReferences[i].APIVersion
|
||||
if meta.OwnerReferences[i].Controller != nil {
|
||||
value := *meta.OwnerReferences[i].Controller
|
||||
ret[i].Controller = &value
|
||||
}
|
||||
if meta.OwnerReferences[i].BlockOwnerDeletion != nil {
|
||||
value := *meta.OwnerReferences[i].BlockOwnerDeletion
|
||||
ret[i].BlockOwnerDeletion = &value
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (meta *ObjectMeta) SetOwnerReferences(references []OwnerReference) {
|
||||
if references == nil {
|
||||
meta.OwnerReferences = nil
|
||||
return
|
||||
}
|
||||
newReferences := make([]OwnerReference, len(references))
|
||||
for i := 0; i < len(references); i++ {
|
||||
newReferences[i].Kind = references[i].Kind
|
||||
newReferences[i].Name = references[i].Name
|
||||
newReferences[i].UID = references[i].UID
|
||||
newReferences[i].APIVersion = references[i].APIVersion
|
||||
if references[i].Controller != nil {
|
||||
value := *references[i].Controller
|
||||
newReferences[i].Controller = &value
|
||||
}
|
||||
if references[i].BlockOwnerDeletion != nil {
|
||||
value := *references[i].BlockOwnerDeletion
|
||||
newReferences[i].BlockOwnerDeletion = &value
|
||||
}
|
||||
}
|
||||
meta.OwnerReferences = newReferences
|
||||
}
|
||||
|
||||
func (meta *ObjectMeta) GetClusterName() string {
|
||||
return meta.ClusterName
|
||||
}
|
||||
func (meta *ObjectMeta) SetClusterName(clusterName string) {
|
||||
meta.ClusterName = clusterName
|
||||
}
|
184
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time.go
generated
vendored
Normal file
184
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time.go
generated
vendored
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
Copyright 2016 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"
|
||||
"time"
|
||||
|
||||
openapi "k8s.io/kube-openapi/pkg/common"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/google/gofuzz"
|
||||
)
|
||||
|
||||
const RFC3339Micro = "2006-01-02T15:04:05.000000Z07:00"
|
||||
|
||||
// MicroTime is version of Time with microsecond level precision.
|
||||
//
|
||||
// +protobuf.options.marshal=false
|
||||
// +protobuf.as=Timestamp
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type MicroTime struct {
|
||||
time.Time `protobuf:"-"`
|
||||
}
|
||||
|
||||
// DeepCopy returns a deep-copy of the MicroTime value. The underlying time.Time
|
||||
// type is effectively immutable in the time API, so it is safe to
|
||||
// copy-by-assign, despite the presence of (unexported) Pointer fields.
|
||||
func (t *MicroTime) DeepCopyInto(out *MicroTime) {
|
||||
*out = *t
|
||||
}
|
||||
|
||||
// String returns the representation of the time.
|
||||
func (t MicroTime) String() string {
|
||||
return t.Time.String()
|
||||
}
|
||||
|
||||
// NewMicroTime returns a wrapped instance of the provided time
|
||||
func NewMicroTime(time time.Time) MicroTime {
|
||||
return MicroTime{time}
|
||||
}
|
||||
|
||||
// DateMicro returns the MicroTime corresponding to the supplied parameters
|
||||
// by wrapping time.Date.
|
||||
func DateMicro(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) MicroTime {
|
||||
return MicroTime{time.Date(year, month, day, hour, min, sec, nsec, loc)}
|
||||
}
|
||||
|
||||
// NowMicro returns the current local time.
|
||||
func NowMicro() MicroTime {
|
||||
return MicroTime{time.Now()}
|
||||
}
|
||||
|
||||
// IsZero returns true if the value is nil or time is zero.
|
||||
func (t *MicroTime) IsZero() bool {
|
||||
if t == nil {
|
||||
return true
|
||||
}
|
||||
return t.Time.IsZero()
|
||||
}
|
||||
|
||||
// Before reports whether the time instant t is before u.
|
||||
func (t *MicroTime) Before(u *MicroTime) bool {
|
||||
return t.Time.Before(u.Time)
|
||||
}
|
||||
|
||||
// Equal reports whether the time instant t is equal to u.
|
||||
func (t *MicroTime) Equal(u *MicroTime) bool {
|
||||
return t.Time.Equal(u.Time)
|
||||
}
|
||||
|
||||
// BeforeTime reports whether the time instant t is before second-lever precision u.
|
||||
func (t *MicroTime) BeforeTime(u *Time) bool {
|
||||
return t.Time.Before(u.Time)
|
||||
}
|
||||
|
||||
// EqualTime reports whether the time instant t is equal to second-lever precision u.
|
||||
func (t *MicroTime) EqualTime(u *Time) bool {
|
||||
return t.Time.Equal(u.Time)
|
||||
}
|
||||
|
||||
// UnixMicro returns the local time corresponding to the given Unix time
|
||||
// by wrapping time.Unix.
|
||||
func UnixMicro(sec int64, nsec int64) MicroTime {
|
||||
return MicroTime{time.Unix(sec, nsec)}
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaller interface.
|
||||
func (t *MicroTime) UnmarshalJSON(b []byte) error {
|
||||
if len(b) == 4 && string(b) == "null" {
|
||||
t.Time = time.Time{}
|
||||
return nil
|
||||
}
|
||||
|
||||
var str string
|
||||
json.Unmarshal(b, &str)
|
||||
|
||||
pt, err := time.Parse(RFC3339Micro, str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Time = pt.Local()
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalQueryParameter converts from a URL query parameter value to an object
|
||||
func (t *MicroTime) UnmarshalQueryParameter(str string) error {
|
||||
if len(str) == 0 {
|
||||
t.Time = time.Time{}
|
||||
return nil
|
||||
}
|
||||
// Tolerate requests from older clients that used JSON serialization to build query params
|
||||
if len(str) == 4 && str == "null" {
|
||||
t.Time = time.Time{}
|
||||
return nil
|
||||
}
|
||||
|
||||
pt, err := time.Parse(RFC3339Micro, str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Time = pt.Local()
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (t MicroTime) MarshalJSON() ([]byte, error) {
|
||||
if t.IsZero() {
|
||||
// Encode unset/nil objects as JSON's "null".
|
||||
return []byte("null"), nil
|
||||
}
|
||||
|
||||
return json.Marshal(t.UTC().Format(RFC3339Micro))
|
||||
}
|
||||
|
||||
func (_ MicroTime) OpenAPIDefinition() openapi.OpenAPIDefinition {
|
||||
return openapi.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "date-time",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalQueryParameter converts to a URL query parameter value
|
||||
func (t MicroTime) MarshalQueryParameter() (string, error) {
|
||||
if t.IsZero() {
|
||||
// Encode unset/nil objects as an empty string
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return t.UTC().Format(RFC3339Micro), nil
|
||||
}
|
||||
|
||||
// Fuzz satisfies fuzz.Interface.
|
||||
func (t *MicroTime) Fuzz(c fuzz.Continue) {
|
||||
if t == nil {
|
||||
return
|
||||
}
|
||||
// Allow for about 1000 years of randomness. Accurate to a tenth of
|
||||
// micro second. Leave off nanoseconds because JSON doesn't
|
||||
// represent them so they can't round-trip properly.
|
||||
t.Time = time.Unix(c.Rand.Int63n(1000*365*24*60*60), 1000*c.Rand.Int63n(1000000))
|
||||
}
|
||||
|
||||
var _ fuzz.Interface = &MicroTime{}
|
72
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_proto.go
generated
vendored
Normal file
72
vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_proto.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright 2016 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 (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Timestamp is declared in time_proto.go
|
||||
|
||||
// Timestamp returns the Time as a new Timestamp value.
|
||||
func (m *MicroTime) ProtoMicroTime() *Timestamp {
|
||||
if m == nil {
|
||||
return &Timestamp{}
|
||||
}
|
||||
return &Timestamp{
|
||||
Seconds: m.Time.Unix(),
|
||||
Nanos: int32(m.Time.Nanosecond()),
|
||||
}
|
||||
}
|
||||
|
||||
// Size implements the protobuf marshalling interface.
|
||||
func (m *MicroTime) Size() (n int) {
|
||||
if m == nil || m.Time.IsZero() {
|
||||
return 0
|
||||
}
|
||||
return m.ProtoMicroTime().Size()
|
||||
}
|
||||
|
||||
// Reset implements the protobuf marshalling interface.
|
||||
func (m *MicroTime) Unmarshal(data []byte) error {
|
||||
if len(data) == 0 {
|
||||
m.Time = time.Time{}
|
||||
return nil
|
||||
}
|
||||
p := Timestamp{}
|
||||
if err := p.Unmarshal(data); err != nil {
|
||||
return err
|
||||
}
|
||||
m.Time = time.Unix(p.Seconds, int64(p.Nanos)).Local()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marshal implements the protobuf marshalling interface.
|
||||
func (m *MicroTime) Marshal() (data []byte, err error) {
|
||||
if m == nil || m.Time.IsZero() {
|
||||
return nil, nil
|
||||
}
|
||||
return m.ProtoMicroTime().Marshal()
|
||||
}
|
||||
|
||||
// MarshalTo implements the protobuf marshalling interface.
|
||||
func (m *MicroTime) MarshalTo(data []byte) (int, error) {
|
||||
if m == nil || m.Time.IsZero() {
|
||||
return 0, nil
|
||||
}
|
||||
return m.ProtoMicroTime().MarshalTo(data)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user