published by bot

(https://github.com/kubernetes/contrib/tree/master/mungegithub)

copied from https://github.com/kubernetes/kubernetes.git, branch master,
last commit is 8d5227bb2e05e01031ace81fa6611a13f598278e
This commit is contained in:
Kubernetes Publisher 2017-01-21 15:19:42 +00:00
parent 98aceecbfb
commit 0eb5431cb7
82 changed files with 2821 additions and 1742 deletions

74
Godeps/Godeps.json generated
View File

@ -324,143 +324,147 @@
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/errors",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/meta",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/fields",
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/labels",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/openapi",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/schema",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/selection",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/types",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/diff",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/errors",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/framer",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/json",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/net",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/rand",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/runtime",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/sets",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation/field",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/wait",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/yaml",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/version",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/watch",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect",
"Rev": "fd5da6b9d070d172e9677941ced569deabdd05ea"
"Rev": "a6364387e6d54a910a0810543a14b6867eafaa99"
}
]
}

View File

@ -33,7 +33,7 @@ import (
"k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
// defaultRetries is the number of times a resource discovery is repeated if an api group disappears on the fly (e.g. ThirdPartyResources).
@ -42,7 +42,7 @@ const defaultRetries = 2
// DiscoveryInterface holds the methods that discover server-supported API groups,
// versions and resources.
type DiscoveryInterface interface {
RESTClient() rest.Interface
RESTClient() restclient.Interface
ServerGroupsInterface
ServerResourcesInterface
ServerVersionInterface
@ -94,7 +94,7 @@ type SwaggerSchemaInterface interface {
// DiscoveryClient implements the functions that discover server-supported API groups,
// versions and resources.
type DiscoveryClient struct {
restClient rest.Interface
restClient restclient.Interface
LegacyPrefix string
}
@ -380,31 +380,31 @@ func withRetries(maxRetries int, f func(failEarly bool) ([]*metav1.APIResourceLi
return result, err
}
func setDiscoveryDefaults(config *rest.Config) error {
func setDiscoveryDefaults(config *restclient.Config) error {
config.APIPath = ""
config.GroupVersion = nil
codec := runtime.NoopEncoder{Decoder: api.Codecs.UniversalDecoder()}
config.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec})
if len(config.UserAgent) == 0 {
config.UserAgent = rest.DefaultKubernetesUserAgent()
config.UserAgent = restclient.DefaultKubernetesUserAgent()
}
return nil
}
// NewDiscoveryClientForConfig creates a new DiscoveryClient for the given config. This client
// can be used to discover supported resources in the API server.
func NewDiscoveryClientForConfig(c *rest.Config) (*DiscoveryClient, error) {
func NewDiscoveryClientForConfig(c *restclient.Config) (*DiscoveryClient, error) {
config := *c
if err := setDiscoveryDefaults(&config); err != nil {
return nil, err
}
client, err := rest.UnversionedRESTClientFor(&config)
client, err := restclient.UnversionedRESTClientFor(&config)
return &DiscoveryClient{restClient: client, LegacyPrefix: "/api"}, err
}
// NewDiscoveryClientForConfig creates a new DiscoveryClient for the given config. If
// there is an error, it panics.
func NewDiscoveryClientForConfigOrDie(c *rest.Config) *DiscoveryClient {
func NewDiscoveryClientForConfigOrDie(c *restclient.Config) *DiscoveryClient {
client, err := NewDiscoveryClientForConfig(c)
if err != nil {
panic(err)
@ -414,7 +414,7 @@ func NewDiscoveryClientForConfigOrDie(c *rest.Config) *DiscoveryClient {
}
// New creates a new DiscoveryClient for the given RESTClient.
func NewDiscoveryClient(c rest.Interface) *DiscoveryClient {
func NewDiscoveryClient(c restclient.Interface) *DiscoveryClient {
return &DiscoveryClient{restClient: c, LegacyPrefix: "/api"}
}
@ -429,7 +429,7 @@ func stringDoesntExistIn(str string, slice []string) bool {
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *DiscoveryClient) RESTClient() rest.Interface {
func (c *DiscoveryClient) RESTClient() restclient.Interface {
if c == nil {
return nil
}

View File

@ -30,7 +30,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
func TestGetServerVersion(t *testing.T) {
@ -50,7 +50,7 @@ func TestGetServerVersion(t *testing.T) {
w.Write(output)
}))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&rest.Config{Host: server.URL})
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
got, err := client.ServerVersion()
if err != nil {
@ -85,7 +85,7 @@ func TestGetServerGroupsWithV1Server(t *testing.T) {
w.Write(output)
}))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&rest.Config{Host: server.URL})
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
// ServerGroups should not return an error even if server returns error at /api and /apis
apiGroupList, err := client.ServerGroups()
if err != nil {
@ -103,7 +103,7 @@ func TestGetServerGroupsWithBrokenServer(t *testing.T) {
w.WriteHeader(statusCode)
}))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&rest.Config{Host: server.URL})
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
// ServerGroups should not return an error even if server returns Not Found or Forbidden error at all end points
apiGroupList, err := client.ServerGroups()
if err != nil {
@ -140,7 +140,7 @@ func TestGetServerResourcesWithV1Server(t *testing.T) {
w.Write(output)
}))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&rest.Config{Host: server.URL})
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
// ServerResources should not return an error even if server returns error at /api/v1.
serverResources, err := client.ServerResources()
if err != nil {
@ -232,7 +232,7 @@ func TestGetServerResources(t *testing.T) {
w.Write(output)
}))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&rest.Config{Host: server.URL})
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
for _, test := range tests {
got, err := client.ServerResourcesForGroupVersion(test.request)
if test.expectErr {
@ -295,7 +295,7 @@ func TestGetSwaggerSchema(t *testing.T) {
}
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&rest.Config{Host: server.URL})
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
got, err := client.SwaggerSchema(v1.SchemeGroupVersion)
if err != nil {
t.Fatalf("unexpected encoding error: %v", err)
@ -314,7 +314,7 @@ func TestGetSwaggerSchemaFail(t *testing.T) {
}
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&rest.Config{Host: server.URL})
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
got, err := client.SwaggerSchema(schema.GroupVersion{Group: "api.group", Version: "v4"})
if got != nil {
t.Fatalf("unexpected response: %v", got)
@ -427,7 +427,7 @@ func TestServerPreferredResources(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(test.response))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&rest.Config{Host: server.URL})
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
resources, err := client.ServerPreferredResources()
if test.expectErr != nil {
if err == nil {
@ -540,7 +540,7 @@ func TestServerPreferredResourcesRetries(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(response(tc.responseErrors)))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&rest.Config{Host: server.URL})
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
resources, err := client.ServerPreferredResources()
if !tc.expectedError(err) {
t.Errorf("case %d: unexpected error: %v", i, err)
@ -711,7 +711,7 @@ func TestServerPreferredNamespacedResources(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(test.response))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&rest.Config{Host: server.URL})
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
resources, err := client.ServerPreferredNamespacedResources()
if err != nil {
t.Errorf("[%d] unexpected error: %v", i, err)

View File

@ -26,7 +26,7 @@ import (
"k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/pkg/api/v1"
kubeversion "k8s.io/client-go/pkg/version"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/testing"
)
@ -92,6 +92,6 @@ func (c *FakeDiscovery) SwaggerSchema(version schema.GroupVersion) (*swagger.Api
return &swagger.ApiDeclaration{}, nil
}
func (c *FakeDiscovery) RESTClient() rest.Interface {
func (c *FakeDiscovery) RESTClient() restclient.Interface {
return nil
}

View File

@ -34,7 +34,7 @@ import (
"k8s.io/client-go/discovery"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/testapi"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
)
@ -139,8 +139,8 @@ func TestNegotiateVersion(t *testing.T) {
return &http.Response{StatusCode: test.statusCode, Header: header, Body: objBody(&uapi.APIVersions{Versions: test.serverVersions})}, nil
}),
}
c := discovery.NewDiscoveryClientForConfigOrDie(&rest.Config{})
c.RESTClient().(*rest.RESTClient).Client = fakeClient.Client
c := discovery.NewDiscoveryClientForConfigOrDie(&restclient.Config{})
c.RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
response, err := discovery.NegotiateVersion(c, test.requiredVersion, test.clientVersions)
if err == nil && test.expectErr != nil {
t.Errorf("expected error, got nil for [%s].", test.name)

View File

@ -25,7 +25,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/version"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
"github.com/emicklei/go-restful/swagger"
@ -246,7 +246,7 @@ func (c *fakeCachedDiscoveryInterface) Invalidate() {
c.enabledA = true
}
func (c *fakeCachedDiscoveryInterface) RESTClient() rest.Interface {
func (c *fakeCachedDiscoveryInterface) RESTClient() restclient.Interface {
return &fake.RESTClient{}
}

View File

@ -37,19 +37,19 @@ import (
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/util/flowcontrol"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
// Client is a Kubernetes client that allows you to access metadata
// and manipulate metadata of a Kubernetes API group.
type Client struct {
cl *rest.RESTClient
cl *restclient.RESTClient
parameterCodec runtime.ParameterCodec
}
// NewClient returns a new client based on the passed in config. The
// codec is ignored, as the dynamic client uses it's own codec.
func NewClient(conf *rest.Config) (*Client, error) {
func NewClient(conf *restclient.Config) (*Client, error) {
// avoid changing the original config
confCopy := *conf
conf = &confCopy
@ -66,10 +66,10 @@ func NewClient(conf *rest.Config) (*Client, error) {
}
if len(conf.UserAgent) == 0 {
conf.UserAgent = rest.DefaultKubernetesUserAgent()
conf.UserAgent = restclient.DefaultKubernetesUserAgent()
}
cl, err := rest.RESTClientFor(conf)
cl, err := restclient.RESTClientFor(conf)
if err != nil {
return nil, err
}
@ -105,7 +105,7 @@ func (c *Client) ParameterCodec(parameterCodec runtime.ParameterCodec) *Client {
// ResourceClient is an API interface to a specific resource under a
// dynamic client.
type ResourceClient struct {
cl *rest.RESTClient
cl *restclient.RESTClient
resource *metav1.APIResource
ns string
parameterCodec runtime.ParameterCodec
@ -242,8 +242,8 @@ func (dynamicCodec) Encode(obj runtime.Object, w io.Writer) error {
return unstructured.UnstructuredJSONScheme.Encode(obj, w)
}
// ContentConfig returns a rest.ContentConfig for dynamic types.
func ContentConfig() rest.ContentConfig {
// ContentConfig returns a restclient.ContentConfig for dynamic types.
func ContentConfig() restclient.ContentConfig {
var jsonInfo runtime.SerializerInfo
// TODO: api.Codecs here should become "pkg/apis/server/scheme" which is the minimal core you need
// to talk to a kubernetes server
@ -256,7 +256,7 @@ func ContentConfig() rest.ContentConfig {
jsonInfo.Serializer = dynamicCodec{}
jsonInfo.PrettySerializer = nil
return rest.ContentConfig{
return restclient.ContentConfig{
AcceptContentTypes: runtime.ContentTypeJSON,
ContentType: runtime.ContentTypeJSON,
NegotiatedSerializer: serializer.NegotiatedSerializerWrapper(jsonInfo),

View File

@ -21,7 +21,7 @@ import (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
// ClientPool manages a pool of dynamic clients.
@ -50,7 +50,7 @@ func LegacyAPIPathResolverFunc(kind schema.GroupVersionKind) string {
// is asked to retrieve. This type is thread safe.
type clientPoolImpl struct {
lock sync.RWMutex
config *rest.Config
config *restclient.Config
clients map[schema.GroupVersion]*Client
apiPathResolverFunc APIPathResolverFunc
mapper meta.RESTMapper
@ -59,7 +59,7 @@ type clientPoolImpl struct {
// NewClientPool returns a ClientPool from the specified config. It reuses clients for the the same
// group version. It is expected this type may be wrapped by specific logic that special cases certain
// resources or groups.
func NewClientPool(config *rest.Config, mapper meta.RESTMapper, apiPathResolverFunc APIPathResolverFunc) ClientPool {
func NewClientPool(config *restclient.Config, mapper meta.RESTMapper, apiPathResolverFunc APIPathResolverFunc) ClientPool {
confCopy := *config
return &clientPoolImpl{

View File

@ -33,7 +33,7 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
restclientwatch "k8s.io/client-go/rest/watch"
)
@ -61,9 +61,9 @@ func getObject(version, kind, name string) *unstructured.Unstructured {
func getClientServer(gv *schema.GroupVersion, h func(http.ResponseWriter, *http.Request)) (*Client, *httptest.Server, error) {
srv := httptest.NewServer(http.HandlerFunc(h))
cl, err := NewClient(&rest.Config{
cl, err := NewClient(&restclient.Config{
Host: srv.URL,
ContentConfig: rest.ContentConfig{GroupVersion: gv},
ContentConfig: restclient.ContentConfig{GroupVersion: gv},
})
if err != nil {
srv.Close()

View File

@ -19,11 +19,11 @@ package v1
import (
"fmt"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/fields"
)
// The EventExpansion interface allows manually adding extra methods to the EventInterface.

View File

@ -17,10 +17,10 @@ limitations under the License.
package fake
import (
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/fields"
"k8s.io/client-go/testing"
)

View File

@ -19,7 +19,7 @@ package fake
import (
"k8s.io/client-go/pkg/api/v1"
policy "k8s.io/client-go/pkg/apis/policy/v1beta1"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/testing"
)
@ -34,7 +34,7 @@ func (c *FakePods) Bind(binding *v1.Binding) error {
return err
}
func (c *FakePods) GetLogs(name string, opts *v1.PodLogOptions) *rest.Request {
func (c *FakePods) GetLogs(name string, opts *v1.PodLogOptions) *restclient.Request {
action := testing.GenericActionImpl{}
action.Verb = "get"
action.Namespace = c.ns
@ -43,7 +43,7 @@ func (c *FakePods) GetLogs(name string, opts *v1.PodLogOptions) *rest.Request {
action.Value = opts
_, _ = c.Fake.Invokes(action, &v1.Pod{})
return &rest.Request{}
return &restclient.Request{}
}
func (c *FakePods) Evict(eviction *policy.Eviction) error {

View File

@ -17,10 +17,10 @@ limitations under the License.
package fake
import (
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/testing"
)
func (c *FakeServices) ProxyGet(scheme, name, port, path string, params map[string]string) rest.ResponseWrapper {
func (c *FakeServices) ProxyGet(scheme, name, port, path string, params map[string]string) restclient.ResponseWrapper {
return c.Fake.InvokesProxy(testing.NewProxyGetAction(servicesResource, c.ns, scheme, name, port, path, params))
}

View File

@ -20,14 +20,14 @@ import (
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/v1"
policy "k8s.io/client-go/pkg/apis/policy/v1beta1"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
// The PodExpansion interface allows manually adding extra methods to the PodInterface.
type PodExpansion interface {
Bind(binding *v1.Binding) error
Evict(eviction *policy.Eviction) error
GetLogs(name string, opts *v1.PodLogOptions) *rest.Request
GetLogs(name string, opts *v1.PodLogOptions) *restclient.Request
}
// Bind applies the provided binding to the named pod in the current namespace (binding.Namespace is ignored).
@ -40,6 +40,6 @@ func (c *pods) Evict(eviction *policy.Eviction) error {
}
// Get constructs a request for getting the logs for a pod
func (c *pods) GetLogs(name string, opts *v1.PodLogOptions) *rest.Request {
func (c *pods) GetLogs(name string, opts *v1.PodLogOptions) *restclient.Request {
return c.client.Get().Namespace(c.ns).Name(name).Resource("pods").SubResource("log").VersionedParams(opts, api.ParameterCodec)
}

View File

@ -18,16 +18,16 @@ package v1
import (
"k8s.io/apimachinery/pkg/util/net"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
// The ServiceExpansion interface allows manually adding extra methods to the ServiceInterface.
type ServiceExpansion interface {
ProxyGet(scheme, name, port, path string, params map[string]string) rest.ResponseWrapper
ProxyGet(scheme, name, port, path string, params map[string]string) restclient.ResponseWrapper
}
// ProxyGet returns a response of the service by calling it through the proxy.
func (c *services) ProxyGet(scheme, name, port, path string, params map[string]string) rest.ResponseWrapper {
func (c *services) ProxyGet(scheme, name, port, path string, params map[string]string) restclient.ResponseWrapper {
request := c.client.Get().
Prefix("proxy").
Namespace(c.ns).

View File

@ -1,20 +0,0 @@
/*
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.
*/
// This package is generated by client-gen with arguments: --clientset-name=release_1_5 --input=[api/v1,apps/v1beta1,authentication/v1beta1,authorization/v1beta1,autoscaling/v1,batch/v1,batch/v2alpha1,certificates/v1alpha1,extensions/v1beta1,policy/v1alpha1,rbac/v1alpha1,storage/v1beta1]
// Package fake has the automatically generated clients.
package fake

View File

@ -1,128 +0,0 @@
/*
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 fake
import (
labels "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
v1 "k8s.io/client-go/pkg/api/v1"
v1alpha1 "k8s.io/client-go/pkg/apis/policy/v1alpha1"
testing "k8s.io/client-go/testing"
)
// FakePodDisruptionBudgets implements PodDisruptionBudgetInterface
type FakePodDisruptionBudgets struct {
Fake *FakePolicyV1alpha1
ns string
}
var poddisruptionbudgetsResource = schema.GroupVersionResource{Group: "policy", Version: "v1alpha1", Resource: "poddisruptionbudgets"}
func (c *FakePodDisruptionBudgets) Create(podDisruptionBudget *v1alpha1.PodDisruptionBudget) (result *v1alpha1.PodDisruptionBudget, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(poddisruptionbudgetsResource, c.ns, podDisruptionBudget), &v1alpha1.PodDisruptionBudget{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.PodDisruptionBudget), err
}
func (c *FakePodDisruptionBudgets) Update(podDisruptionBudget *v1alpha1.PodDisruptionBudget) (result *v1alpha1.PodDisruptionBudget, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(poddisruptionbudgetsResource, c.ns, podDisruptionBudget), &v1alpha1.PodDisruptionBudget{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.PodDisruptionBudget), err
}
func (c *FakePodDisruptionBudgets) UpdateStatus(podDisruptionBudget *v1alpha1.PodDisruptionBudget) (*v1alpha1.PodDisruptionBudget, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(poddisruptionbudgetsResource, "status", c.ns, podDisruptionBudget), &v1alpha1.PodDisruptionBudget{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.PodDisruptionBudget), err
}
func (c *FakePodDisruptionBudgets) Delete(name string, options *v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(poddisruptionbudgetsResource, c.ns, name), &v1alpha1.PodDisruptionBudget{})
return err
}
func (c *FakePodDisruptionBudgets) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(poddisruptionbudgetsResource, c.ns, listOptions)
_, err := c.Fake.Invokes(action, &v1alpha1.PodDisruptionBudgetList{})
return err
}
func (c *FakePodDisruptionBudgets) Get(name string) (result *v1alpha1.PodDisruptionBudget, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(poddisruptionbudgetsResource, c.ns, name), &v1alpha1.PodDisruptionBudget{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.PodDisruptionBudget), err
}
func (c *FakePodDisruptionBudgets) List(opts v1.ListOptions) (result *v1alpha1.PodDisruptionBudgetList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(poddisruptionbudgetsResource, c.ns, opts), &v1alpha1.PodDisruptionBudgetList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha1.PodDisruptionBudgetList{}
for _, item := range obj.(*v1alpha1.PodDisruptionBudgetList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested podDisruptionBudgets.
func (c *FakePodDisruptionBudgets) Watch(opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(poddisruptionbudgetsResource, c.ns, opts))
}
// Patch applies the patch and returns the patched podDisruptionBudget.
func (c *FakePodDisruptionBudgets) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.PodDisruptionBudget, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(poddisruptionbudgetsResource, c.ns, name, data, subresources...), &v1alpha1.PodDisruptionBudget{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.PodDisruptionBudget), err
}

View File

@ -1,38 +0,0 @@
/*
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 fake
import (
v1alpha1 "k8s.io/client-go/kubernetes/typed/policy/v1alpha1"
rest "k8s.io/client-go/rest"
testing "k8s.io/client-go/testing"
)
type FakePolicyV1alpha1 struct {
*testing.Fake
}
func (c *FakePolicyV1alpha1) PodDisruptionBudgets(namespace string) v1alpha1.PodDisruptionBudgetInterface {
return &FakePodDisruptionBudgets{c, namespace}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakePolicyV1alpha1) RESTClient() rest.Interface {
var ret *rest.RESTClient
return ret
}

View File

@ -1,168 +0,0 @@
/*
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 v1alpha1
import (
"k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
api "k8s.io/client-go/pkg/api"
v1 "k8s.io/client-go/pkg/api/v1"
v1alpha1 "k8s.io/client-go/pkg/apis/policy/v1alpha1"
rest "k8s.io/client-go/rest"
)
// PodDisruptionBudgetsGetter has a method to return a PodDisruptionBudgetInterface.
// A group's client should implement this interface.
type PodDisruptionBudgetsGetter interface {
PodDisruptionBudgets(namespace string) PodDisruptionBudgetInterface
}
// PodDisruptionBudgetInterface has methods to work with PodDisruptionBudget resources.
type PodDisruptionBudgetInterface interface {
Create(*v1alpha1.PodDisruptionBudget) (*v1alpha1.PodDisruptionBudget, error)
Update(*v1alpha1.PodDisruptionBudget) (*v1alpha1.PodDisruptionBudget, error)
UpdateStatus(*v1alpha1.PodDisruptionBudget) (*v1alpha1.PodDisruptionBudget, error)
Delete(name string, options *v1.DeleteOptions) error
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
Get(name string) (*v1alpha1.PodDisruptionBudget, error)
List(opts v1.ListOptions) (*v1alpha1.PodDisruptionBudgetList, error)
Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.PodDisruptionBudget, err error)
PodDisruptionBudgetExpansion
}
// podDisruptionBudgets implements PodDisruptionBudgetInterface
type podDisruptionBudgets struct {
client rest.Interface
ns string
}
// newPodDisruptionBudgets returns a PodDisruptionBudgets
func newPodDisruptionBudgets(c *PolicyV1alpha1Client, namespace string) *podDisruptionBudgets {
return &podDisruptionBudgets{
client: c.RESTClient(),
ns: namespace,
}
}
// Create takes the representation of a podDisruptionBudget and creates it. Returns the server's representation of the podDisruptionBudget, and an error, if there is any.
func (c *podDisruptionBudgets) Create(podDisruptionBudget *v1alpha1.PodDisruptionBudget) (result *v1alpha1.PodDisruptionBudget, err error) {
result = &v1alpha1.PodDisruptionBudget{}
err = c.client.Post().
Namespace(c.ns).
Resource("poddisruptionbudgets").
Body(podDisruptionBudget).
Do().
Into(result)
return
}
// Update takes the representation of a podDisruptionBudget and updates it. Returns the server's representation of the podDisruptionBudget, and an error, if there is any.
func (c *podDisruptionBudgets) Update(podDisruptionBudget *v1alpha1.PodDisruptionBudget) (result *v1alpha1.PodDisruptionBudget, err error) {
result = &v1alpha1.PodDisruptionBudget{}
err = c.client.Put().
Namespace(c.ns).
Resource("poddisruptionbudgets").
Name(podDisruptionBudget.Name).
Body(podDisruptionBudget).
Do().
Into(result)
return
}
func (c *podDisruptionBudgets) UpdateStatus(podDisruptionBudget *v1alpha1.PodDisruptionBudget) (result *v1alpha1.PodDisruptionBudget, err error) {
result = &v1alpha1.PodDisruptionBudget{}
err = c.client.Put().
Namespace(c.ns).
Resource("poddisruptionbudgets").
Name(podDisruptionBudget.Name).
SubResource("status").
Body(podDisruptionBudget).
Do().
Into(result)
return
}
// Delete takes name of the podDisruptionBudget and deletes it. Returns an error if one occurs.
func (c *podDisruptionBudgets) Delete(name string, options *v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("poddisruptionbudgets").
Name(name).
Body(options).
Do().
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *podDisruptionBudgets) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("poddisruptionbudgets").
VersionedParams(&listOptions, api.ParameterCodec).
Body(options).
Do().
Error()
}
// Get takes name of the podDisruptionBudget, and returns the corresponding podDisruptionBudget object, and an error if there is any.
func (c *podDisruptionBudgets) Get(name string) (result *v1alpha1.PodDisruptionBudget, err error) {
result = &v1alpha1.PodDisruptionBudget{}
err = c.client.Get().
Namespace(c.ns).
Resource("poddisruptionbudgets").
Name(name).
Do().
Into(result)
return
}
// List takes label and field selectors, and returns the list of PodDisruptionBudgets that match those selectors.
func (c *podDisruptionBudgets) List(opts v1.ListOptions) (result *v1alpha1.PodDisruptionBudgetList, err error) {
result = &v1alpha1.PodDisruptionBudgetList{}
err = c.client.Get().
Namespace(c.ns).
Resource("poddisruptionbudgets").
VersionedParams(&opts, api.ParameterCodec).
Do().
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested podDisruptionBudgets.
func (c *podDisruptionBudgets) Watch(opts v1.ListOptions) (watch.Interface, error) {
return c.client.Get().
Prefix("watch").
Namespace(c.ns).
Resource("poddisruptionbudgets").
VersionedParams(&opts, api.ParameterCodec).
Watch()
}
// Patch applies the patch and returns the patched podDisruptionBudget.
func (c *podDisruptionBudgets) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.PodDisruptionBudget, err error) {
result = &v1alpha1.PodDisruptionBudget{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("poddisruptionbudgets").
SubResource(subresources...).
Name(name).
Body(data).
Do().
Into(result)
return
}

View File

@ -1,98 +0,0 @@
/*
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 v1alpha1
import (
fmt "fmt"
"k8s.io/apimachinery/pkg/runtime/schema"
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
api "k8s.io/client-go/pkg/api"
rest "k8s.io/client-go/rest"
)
type PolicyV1alpha1Interface interface {
RESTClient() rest.Interface
PodDisruptionBudgetsGetter
}
// PolicyV1alpha1Client is used to interact with features provided by the k8s.io/kubernetes/pkg/apimachinery/registered.Group group.
type PolicyV1alpha1Client struct {
restClient rest.Interface
}
func (c *PolicyV1alpha1Client) PodDisruptionBudgets(namespace string) PodDisruptionBudgetInterface {
return newPodDisruptionBudgets(c, namespace)
}
// NewForConfig creates a new PolicyV1alpha1Client for the given config.
func NewForConfig(c *rest.Config) (*PolicyV1alpha1Client, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
}
client, err := rest.RESTClientFor(&config)
if err != nil {
return nil, err
}
return &PolicyV1alpha1Client{client}, nil
}
// NewForConfigOrDie creates a new PolicyV1alpha1Client for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *PolicyV1alpha1Client {
client, err := NewForConfig(c)
if err != nil {
panic(err)
}
return client
}
// New creates a new PolicyV1alpha1Client for the given RESTClient.
func New(c rest.Interface) *PolicyV1alpha1Client {
return &PolicyV1alpha1Client{c}
}
func setConfigDefaults(config *rest.Config) error {
gv, err := schema.ParseGroupVersion("policy/v1alpha1")
if err != nil {
return err
}
// if policy/v1alpha1 is not enabled, return an error
if !api.Registry.IsEnabledVersion(gv) {
return fmt.Errorf("policy/v1alpha1 is not enabled")
}
config.APIPath = "/apis"
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}
copyGroupVersion := gv
config.GroupVersion = &copyGroupVersion
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: api.Codecs}
return nil
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *PolicyV1alpha1Client) RESTClient() rest.Interface {
if c == nil {
return nil
}
return c.restClient
}

View File

@ -21,11 +21,11 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"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/validation/field"
"k8s.io/client-go/pkg/api/resource"
"k8s.io/client-go/pkg/fields"
"k8s.io/client-go/pkg/util/intstr"
utillabels "k8s.io/client-go/pkg/util/labels"
)

View File

@ -17,9 +17,9 @@ limitations under the License.
package api
import (
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/pkg/fields"
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {

View File

@ -27,13 +27,13 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/pkg/api/resource"
"k8s.io/client-go/pkg/fields"
)
// Conversion error conveniently packages up errors in conversions.

View File

@ -18,11 +18,11 @@ package api
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.io/apimachinery/pkg/types"
"k8s.io/client-go/pkg/api/resource"
"k8s.io/client-go/pkg/fields"
"k8s.io/client-go/pkg/util/intstr"
)
@ -1856,6 +1856,10 @@ type PodSpec struct {
// If specified, the pod's scheduling constraints
// +optional
Affinity *Affinity
// If specified, the pod will be dispatched by specified scheduler.
// If not specified, the pod will be dispatched by default scheduler.
// +optional
SchedulerName string
}
// Sysctl defines a kernel parameter to be set

View File

@ -174,6 +174,9 @@ func SetDefaults_PodSpec(obj *PodSpec) {
period := int64(DefaultTerminationGracePeriodSeconds)
obj.TerminationGracePeriodSeconds = &period
}
if obj.SchedulerName == "" {
obj.SchedulerName = DefaultSchedulerName
}
}
func SetDefaults_Probe(obj *Probe) {
if obj.TimeoutSeconds == 0 {

File diff suppressed because it is too large Load Diff

View File

@ -2553,6 +2553,11 @@ message PodSpec {
// If specified, the pod's scheduling constraints
// +optional
optional Affinity affinity = 18;
// If specified, the pod will be dispatched by specified scheduler.
// If not specified, the pod will be dispatched by default scheduler.
// +optional
optional string schedulername = 19;
}
// PodStatus represents information about the status of a pod. Status may trail the actual

View File

@ -22,12 +22,12 @@ import (
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/fields"
)
// IsOpaqueIntResourceName returns true if the resource name has the opaque

View File

@ -29772,7 +29772,7 @@ func (x *PodSpec) CodecEncodeSelf(e *codec1978.Encoder) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [18]bool
var yyq2 [19]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[0] = len(x.Volumes) != 0
@ -29792,9 +29792,10 @@ func (x *PodSpec) CodecEncodeSelf(e *codec1978.Encoder) {
yyq2[15] = x.Hostname != ""
yyq2[16] = x.Subdomain != ""
yyq2[17] = x.Affinity != nil
yyq2[18] = x.SchedulerName != ""
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(18)
r.EncodeArrayStart(19)
} else {
yynn2 = 1
for _, b := range yyq2 {
@ -30277,6 +30278,31 @@ func (x *PodSpec) CodecEncodeSelf(e *codec1978.Encoder) {
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[18] {
yym62 := z.EncBinary()
_ = yym62
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.SchedulerName))
}
} else {
r.EncodeString(codecSelferC_UTF81234, "")
}
} else {
if yyq2[18] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("schedulername"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym63 := z.EncBinary()
_ = yym63
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.SchedulerName))
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
@ -30550,6 +30576,18 @@ func (x *PodSpec) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
}
x.Affinity.CodecDecodeSelf(d)
}
case "schedulername":
if r.TryDecodeAsNil() {
x.SchedulerName = ""
} else {
yyv36 := &x.SchedulerName
yym37 := z.DecBinary()
_ = yym37
if false {
} else {
*((*string)(yyv36)) = r.DecodeString()
}
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
@ -30561,16 +30599,16 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj36 int
var yyb36 bool
var yyhl36 bool = l >= 0
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
var yyj38 int
var yyb38 bool
var yyhl38 bool = l >= 0
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -30578,21 +30616,21 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() {
x.Volumes = nil
} else {
yyv37 := &x.Volumes
yym38 := z.DecBinary()
_ = yym38
yyv39 := &x.Volumes
yym40 := z.DecBinary()
_ = yym40
if false {
} else {
h.decSliceVolume((*[]Volume)(yyv37), d)
h.decSliceVolume((*[]Volume)(yyv39), d)
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -30600,21 +30638,21 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() {
x.Containers = nil
} else {
yyv39 := &x.Containers
yym40 := z.DecBinary()
_ = yym40
yyv41 := &x.Containers
yym42 := z.DecBinary()
_ = yym42
if false {
} else {
h.decSliceContainer((*[]Container)(yyv39), d)
h.decSliceContainer((*[]Container)(yyv41), d)
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -30622,16 +30660,16 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() {
x.RestartPolicy = ""
} else {
yyv41 := &x.RestartPolicy
yyv41.CodecDecodeSelf(d)
yyv43 := &x.RestartPolicy
yyv43.CodecDecodeSelf(d)
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -30644,20 +30682,20 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if x.TerminationGracePeriodSeconds == nil {
x.TerminationGracePeriodSeconds = new(int64)
}
yym43 := z.DecBinary()
_ = yym43
yym45 := z.DecBinary()
_ = yym45
if false {
} else {
*((*int64)(x.TerminationGracePeriodSeconds)) = int64(r.DecodeInt(64))
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -30670,20 +30708,20 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if x.ActiveDeadlineSeconds == nil {
x.ActiveDeadlineSeconds = new(int64)
}
yym45 := z.DecBinary()
_ = yym45
yym47 := z.DecBinary()
_ = yym47
if false {
} else {
*((*int64)(x.ActiveDeadlineSeconds)) = int64(r.DecodeInt(64))
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -30691,16 +30729,16 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() {
x.DNSPolicy = ""
} else {
yyv46 := &x.DNSPolicy
yyv46.CodecDecodeSelf(d)
yyv48 := &x.DNSPolicy
yyv48.CodecDecodeSelf(d)
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -30708,21 +30746,21 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() {
x.NodeSelector = nil
} else {
yyv47 := &x.NodeSelector
yym48 := z.DecBinary()
_ = yym48
yyv49 := &x.NodeSelector
yym50 := z.DecBinary()
_ = yym50
if false {
} else {
z.F.DecMapStringStringX(yyv47, false, d)
z.F.DecMapStringStringX(yyv49, false, d)
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -30730,29 +30768,7 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() {
x.ServiceAccountName = ""
} else {
yyv49 := &x.ServiceAccountName
yym50 := z.DecBinary()
_ = yym50
if false {
} else {
*((*string)(yyv49)) = r.DecodeString()
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
} else {
yyb36 = r.CheckBreak()
}
if yyb36 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.DeprecatedServiceAccount = ""
} else {
yyv51 := &x.DeprecatedServiceAccount
yyv51 := &x.ServiceAccountName
yym52 := z.DecBinary()
_ = yym52
if false {
@ -30760,21 +30776,21 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
*((*string)(yyv51)) = r.DecodeString()
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.NodeName = ""
x.DeprecatedServiceAccount = ""
} else {
yyv53 := &x.NodeName
yyv53 := &x.DeprecatedServiceAccount
yym54 := z.DecBinary()
_ = yym54
if false {
@ -30782,13 +30798,35 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
*((*string)(yyv53)) = r.DecodeString()
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.NodeName = ""
} else {
yyv55 := &x.NodeName
yym56 := z.DecBinary()
_ = yym56
if false {
} else {
*((*string)(yyv55)) = r.DecodeString()
}
}
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb38 = r.CheckBreak()
}
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -30796,29 +30834,7 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() {
x.HostNetwork = false
} else {
yyv55 := &x.HostNetwork
yym56 := z.DecBinary()
_ = yym56
if false {
} else {
*((*bool)(yyv55)) = r.DecodeBool()
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
} else {
yyb36 = r.CheckBreak()
}
if yyb36 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.HostPID = false
} else {
yyv57 := &x.HostPID
yyv57 := &x.HostNetwork
yym58 := z.DecBinary()
_ = yym58
if false {
@ -30826,21 +30842,21 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
*((*bool)(yyv57)) = r.DecodeBool()
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.HostIPC = false
x.HostPID = false
} else {
yyv59 := &x.HostIPC
yyv59 := &x.HostPID
yym60 := z.DecBinary()
_ = yym60
if false {
@ -30848,13 +30864,35 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
*((*bool)(yyv59)) = r.DecodeBool()
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.HostIPC = false
} else {
yyv61 := &x.HostIPC
yym62 := z.DecBinary()
_ = yym62
if false {
} else {
*((*bool)(yyv61)) = r.DecodeBool()
}
}
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb38 = r.CheckBreak()
}
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -30869,13 +30907,13 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
}
x.SecurityContext.CodecDecodeSelf(d)
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -30883,21 +30921,21 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() {
x.ImagePullSecrets = nil
} else {
yyv62 := &x.ImagePullSecrets
yym63 := z.DecBinary()
_ = yym63
yyv64 := &x.ImagePullSecrets
yym65 := z.DecBinary()
_ = yym65
if false {
} else {
h.decSliceLocalObjectReference((*[]LocalObjectReference)(yyv62), d)
h.decSliceLocalObjectReference((*[]LocalObjectReference)(yyv64), d)
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -30905,29 +30943,7 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
if r.TryDecodeAsNil() {
x.Hostname = ""
} else {
yyv64 := &x.Hostname
yym65 := z.DecBinary()
_ = yym65
if false {
} else {
*((*string)(yyv64)) = r.DecodeString()
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
} else {
yyb36 = r.CheckBreak()
}
if yyb36 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Subdomain = ""
} else {
yyv66 := &x.Subdomain
yyv66 := &x.Hostname
yym67 := z.DecBinary()
_ = yym67
if false {
@ -30935,13 +30951,35 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
*((*string)(yyv66)) = r.DecodeString()
}
}
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb36 = r.CheckBreak()
yyb38 = r.CheckBreak()
}
if yyb36 {
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Subdomain = ""
} else {
yyv68 := &x.Subdomain
yym69 := z.DecBinary()
_ = yym69
if false {
} else {
*((*string)(yyv68)) = r.DecodeString()
}
}
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb38 = r.CheckBreak()
}
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -30956,18 +30994,40 @@ func (x *PodSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
}
x.Affinity.CodecDecodeSelf(d)
}
for {
yyj36++
if yyhl36 {
yyb36 = yyj36 > l
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb38 = r.CheckBreak()
}
if yyb38 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.SchedulerName = ""
} else {
yyv71 := &x.SchedulerName
yym72 := z.DecBinary()
_ = yym72
if false {
} else {
yyb36 = r.CheckBreak()
*((*string)(yyv71)) = r.DecodeString()
}
if yyb36 {
}
for {
yyj38++
if yyhl38 {
yyb38 = yyj38 > l
} else {
yyb38 = r.CheckBreak()
}
if yyb38 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj36-1, "")
z.DecStructFieldNotFound(yyj38-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}
@ -64225,7 +64285,7 @@ func (x codecSelfer1234) decSlicePod(v *[]Pod, d *codec1978.Decoder) {
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 688)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 704)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
@ -64344,7 +64404,7 @@ func (x codecSelfer1234) decSlicePodTemplate(v *[]PodTemplate, d *codec1978.Deco
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 736)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 752)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]

View File

@ -2140,6 +2140,10 @@ type PodSpec struct {
// If specified, the pod's scheduling constraints
// +optional
Affinity *Affinity `json:"affinity,omitempty" protobuf:"bytes,18,opt,name=affinity"`
// If specified, the pod will be dispatched by specified scheduler.
// If not specified, the pod will be dispatched by default scheduler.
// +optional
SchedulerName string `json:"schedulername,omitempty" protobuf:"bytes,19,opt,name=schedulername"`
}
// PodSecurityContext holds pod-level security attributes and common container settings.

View File

@ -1294,6 +1294,7 @@ var map_PodSpec = map[string]string{
"hostname": "Specifies the hostname of the Pod If not specified, the pod's hostname will be set to a system-defined value.",
"subdomain": "If specified, the fully qualified Pod hostname will be \"<hostname>.<subdomain>.<pod namespace>.svc.<cluster domain>\". If not specified, the pod will not have a domainname at all.",
"affinity": "If specified, the pod's scheduling constraints",
"schedulername": "If specified, the pod will be dispatched by specified scheduler. If not specified, the pod will be dispatched by default scheduler.",
}
func (PodSpec) SwaggerDoc() map[string]string {

View File

@ -3069,6 +3069,7 @@ func autoConvert_v1_PodSpec_To_api_PodSpec(in *PodSpec, out *api.PodSpec, s conv
out.Hostname = in.Hostname
out.Subdomain = in.Subdomain
out.Affinity = (*api.Affinity)(unsafe.Pointer(in.Affinity))
out.SchedulerName = in.SchedulerName
return nil
}
@ -3106,6 +3107,7 @@ func autoConvert_api_PodSpec_To_v1_PodSpec(in *api.PodSpec, out *PodSpec, s conv
out.Hostname = in.Hostname
out.Subdomain = in.Subdomain
out.Affinity = (*Affinity)(unsafe.Pointer(in.Affinity))
out.SchedulerName = in.SchedulerName
return nil
}

View File

@ -1,68 +0,0 @@
/*
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)
}
}

View File

@ -23,10 +23,10 @@ package api
import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion"
fields "k8s.io/apimachinery/pkg/fields"
labels "k8s.io/apimachinery/pkg/labels"
runtime "k8s.io/apimachinery/pkg/runtime"
types "k8s.io/apimachinery/pkg/types"
fields "k8s.io/client-go/pkg/fields"
reflect "reflect"
)

View File

@ -1679,7 +1679,7 @@ func (x codecSelfer1234) decSliceStatefulSet(v *[]StatefulSet, d *codec1978.Deco
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 808)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 824)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]

View File

@ -2481,7 +2481,7 @@ func (x codecSelfer1234) decSliceJob(v *[]Job, d *codec1978.Decoder) {
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 832)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 848)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]

View File

@ -4534,7 +4534,7 @@ func (x codecSelfer1234) decSliceJob(v *[]Job, d *codec1978.Decoder) {
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 832)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 848)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
@ -4772,7 +4772,7 @@ func (x codecSelfer1234) decSliceCronJob(v *[]CronJob, d *codec1978.Decoder) {
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 1080)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 1096)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]

View File

@ -21093,7 +21093,7 @@ func (x codecSelfer1234) decSliceDeployment(v *[]Deployment, d *codec1978.Decode
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 872)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 888)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
@ -21212,7 +21212,7 @@ func (x codecSelfer1234) decSliceDaemonSet(v *[]DaemonSet, d *codec1978.Decoder)
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 768)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 784)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
@ -21926,7 +21926,7 @@ func (x codecSelfer1234) decSliceReplicaSet(v *[]ReplicaSet, d *codec1978.Decode
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 808)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 824)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]

View File

@ -39,6 +39,7 @@ type MasterConfiguration struct {
Networking Networking
KubernetesVersion string
CloudProvider string
AuthorizationMode string
}
type API struct {

View File

@ -16,9 +16,7 @@ limitations under the License.
package v1alpha1
import (
"k8s.io/apimachinery/pkg/runtime"
)
import "k8s.io/apimachinery/pkg/runtime"
const (
DefaultServiceDNSDomain = "cluster.local"
@ -27,6 +25,7 @@ const (
DefaultKubernetesFallbackVersion = "v1.5.0"
DefaultAPIBindPort = 6443
DefaultDiscoveryBindPort = 9898
DefaultAuthorizationMode = "RBAC"
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
@ -56,4 +55,8 @@ func SetDefaults_MasterConfiguration(obj *MasterConfiguration) {
if obj.Discovery.Token == nil && obj.Discovery.File == nil && obj.Discovery.HTTPS == nil {
obj.Discovery.Token = &TokenDiscovery{}
}
if obj.AuthorizationMode == "" {
obj.AuthorizationMode = DefaultAuthorizationMode
}
}

View File

@ -29,6 +29,7 @@ type MasterConfiguration struct {
Networking Networking `json:"networking"`
KubernetesVersion string `json:"kubernetesVersion"`
CloudProvider string `json:"cloudProvider"`
AuthorizationMode string `json:"authorizationMode"`
}
type API struct {

View File

@ -1,20 +0,0 @@
/*
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 policy is for any kind of policy object. Suitable examples, even if
// they aren't all here, are PodDisruptionBudget, PodSecurityPolicy,
// NetworkPolicy, etc.
package v1alpha1

View File

@ -1,56 +0,0 @@
/*
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 v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/pkg/api/v1"
)
// GroupName is the group name use in this package
const GroupName = "policy"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&PodDisruptionBudget{},
&PodDisruptionBudgetList{},
&Eviction{},
&v1.ListOptions{},
&v1.DeleteOptions{},
&metav1.ExportOptions{},
&metav1.GetOptions{},
)
// Add the watch version that applies
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}

View File

@ -1,93 +0,0 @@
/*
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 v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/util/intstr"
)
// PodDisruptionBudgetSpec is a description of a PodDisruptionBudget.
type PodDisruptionBudgetSpec struct {
// An eviction is allowed if at least "minAvailable" pods selected by
// "selector" will still be available after the eviction, i.e. even in the
// absence of the evicted pod. So for example you can prevent all voluntary
// evictions by specifying "100%".
// +optional
MinAvailable intstr.IntOrString `json:"minAvailable,omitempty" protobuf:"bytes,1,opt,name=minAvailable"`
// Label query over pods whose evictions are managed by the disruption
// budget.
// +optional
Selector *metav1.LabelSelector `json:"selector,omitempty" protobuf:"bytes,2,opt,name=selector"`
}
// PodDisruptionBudgetStatus represents information about the status of a
// PodDisruptionBudget. Status may trail the actual state of a system.
type PodDisruptionBudgetStatus struct {
// Whether or not a disruption is currently allowed.
PodDisruptionAllowed bool `json:"disruptionAllowed" protobuf:"varint,1,opt,name=disruptionAllowed"`
// current number of healthy pods
CurrentHealthy int32 `json:"currentHealthy" protobuf:"varint,2,opt,name=currentHealthy"`
// minimum desired number of healthy pods
DesiredHealthy int32 `json:"desiredHealthy" protobuf:"varint,3,opt,name=desiredHealthy"`
// total number of pods counted by this disruption budget
ExpectedPods int32 `json:"expectedPods" protobuf:"varint,4,opt,name=expectedPods"`
}
// +genclient=true
// PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods
type PodDisruptionBudget struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Specification of the desired behavior of the PodDisruptionBudget.
// +optional
Spec PodDisruptionBudgetSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
// Most recently observed status of the PodDisruptionBudget.
// +optional
Status PodDisruptionBudgetStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}
// PodDisruptionBudgetList is a collection of PodDisruptionBudgets.
type PodDisruptionBudgetList struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Items []PodDisruptionBudget `json:"items" protobuf:"bytes,2,rep,name=items"`
}
// Eviction evicts a pod from its node subject to certain policies and safety constraints.
// This is a subresource of Pod. A request to cause such an eviction is
// created by POSTing to .../pods/<pod name>/eviction.
type Eviction struct {
metav1.TypeMeta `json:",inline"`
// ObjectMeta describes the pod that is being evicted.
// +optional
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// DeleteOptions may be provided
// +optional
DeleteOptions *v1.DeleteOptions `json:"deleteOptions,omitempty" protobuf:"bytes,2,opt,name=deleteOptions"`
}

View File

@ -25,6 +25,7 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"fmt"
"math"
"math/big"
@ -42,6 +43,7 @@ type Config struct {
CommonName string
Organization []string
AltNames AltNames
Usages []x509.ExtKeyUsage
}
// AltNames contains the domain names and IP addresses that will be added
@ -86,11 +88,17 @@ func NewSignedCert(cfg Config, key *rsa.PrivateKey, caCert *x509.Certificate, ca
if err != nil {
return nil, err
}
if len(cfg.CommonName) == 0 {
return nil, errors.New("must specify a CommonName")
}
if len(cfg.Usages) == 0 {
return nil, errors.New("must specify at least one ExtKeyUsage")
}
certTmpl := x509.Certificate{
Subject: pkix.Name{
CommonName: cfg.CommonName,
Organization: caCert.Subject.Organization,
Organization: cfg.Organization,
},
DNSNames: cfg.AltNames.DNSNames,
IPAddresses: cfg.AltNames.IPs,
@ -98,7 +106,7 @@ func NewSignedCert(cfg Config, key *rsa.PrivateKey, caCert *x509.Certificate, ca
NotBefore: caCert.NotBefore,
NotAfter: time.Now().Add(duration365d).UTC(),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
ExtKeyUsage: cfg.Usages,
}
certDERBytes, err := x509.CreateCertificate(cryptorand.Reader, &certTmpl, caCert, key.Public(), caKey)
if err != nil {

View File

@ -14,7 +14,33 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// This package is generated by client-gen with arguments: --clientset-name=release_1_5 --input=[api/v1,apps/v1beta1,authentication/v1beta1,authorization/v1beta1,autoscaling/v1,batch/v1,batch/v2alpha1,certificates/v1alpha1,extensions/v1beta1,policy/v1alpha1,rbac/v1alpha1,storage/v1beta1]
package cert
// This package has the automatically generated typed clients.
package v1alpha1
import (
"crypto/x509/pkix"
"io/ioutil"
"net"
"testing"
)
func TestMakeCSR(t *testing.T) {
keyFile := "testdata/dontUseThisKey.pem"
subject := &pkix.Name{
CommonName: "kube-worker",
}
dnsSANs := []string{"localhost"}
ipSANs := []net.IP{net.ParseIP("127.0.0.1")}
keyData, err := ioutil.ReadFile(keyFile)
if err != nil {
t.Fatal(err)
}
key, err := ParsePrivateKeyPEM(keyData)
if err != nil {
t.Fatal(err)
}
_, err = MakeCSR(key, subject, dnsSANs, ipSANs)
if err != nil {
t.Error(err)
}
}

View File

@ -0,0 +1,6 @@
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDAPEbSXwyDfWf0+61Oofd7aHkmdX69mrzD2Xb1CHF5syfsoRIhnG0dJ
ozBulPZCDDWgBwYFK4EEACKhZANiAATjlMJAtKhEPqU/i7MsrgKcK/RmXHC6He7W
0p69+9qFXg2raJ9zvvbKxkiu2ELOYRDAz0utcFTBOIgoUJEzBVmsjZQ7dvFa1BKP
Ym7MFAKG3O2espBqXn+audgdHGh5B0I=
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,116 @@
/*
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 triple generates key-certificate pairs for the
// triple (CA, Server, Client).
package triple
import (
"crypto/rsa"
"crypto/x509"
"fmt"
"net"
certutil "k8s.io/client-go/pkg/util/cert"
)
type KeyPair struct {
Key *rsa.PrivateKey
Cert *x509.Certificate
}
func NewCA(name string) (*KeyPair, error) {
key, err := certutil.NewPrivateKey()
if err != nil {
return nil, fmt.Errorf("unable to create a private key for a new CA: %v", err)
}
config := certutil.Config{
CommonName: name,
}
cert, err := certutil.NewSelfSignedCACert(config, key)
if err != nil {
return nil, fmt.Errorf("unable to create a self-signed certificate for a new CA: %v", err)
}
return &KeyPair{
Key: key,
Cert: cert,
}, nil
}
func NewServerKeyPair(ca *KeyPair, commonName, svcName, svcNamespace, dnsDomain string, ips, hostnames []string) (*KeyPair, error) {
key, err := certutil.NewPrivateKey()
if err != nil {
return nil, fmt.Errorf("unable to create a server private key: %v", err)
}
namespacedName := fmt.Sprintf("%s.%s", svcName, svcNamespace)
internalAPIServerFQDN := []string{
svcName,
namespacedName,
fmt.Sprintf("%s.svc", namespacedName),
fmt.Sprintf("%s.svc.%s", namespacedName, dnsDomain),
}
altNames := certutil.AltNames{}
for _, ipStr := range ips {
ip := net.ParseIP(ipStr)
if ip != nil {
altNames.IPs = append(altNames.IPs, ip)
}
}
altNames.DNSNames = append(altNames.DNSNames, hostnames...)
altNames.DNSNames = append(altNames.DNSNames, internalAPIServerFQDN...)
config := certutil.Config{
CommonName: commonName,
AltNames: altNames,
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
}
cert, err := certutil.NewSignedCert(config, key, ca.Cert, ca.Key)
if err != nil {
return nil, fmt.Errorf("unable to sign the server certificate: %v", err)
}
return &KeyPair{
Key: key,
Cert: cert,
}, nil
}
func NewClientKeyPair(ca *KeyPair, commonName string, organizations []string) (*KeyPair, error) {
key, err := certutil.NewPrivateKey()
if err != nil {
return nil, fmt.Errorf("unable to create a client private key: %v", err)
}
config := certutil.Config{
CommonName: commonName,
Organization: organizations,
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
cert, err := certutil.NewSignedCert(config, key, ca.Cert, ca.Key)
if err != nil {
return nil, fmt.Errorf("unable to sign the client certificate: %v", err)
}
return &KeyPair{
Key: key,
Cert: cert,
}, nil
}

View File

@ -0,0 +1,184 @@
/*
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 clock
import (
"testing"
"time"
)
func TestFakeClock(t *testing.T) {
startTime := time.Now()
tc := NewFakeClock(startTime)
tc.Step(time.Second)
now := tc.Now()
if now.Sub(startTime) != time.Second {
t.Errorf("input: %s now=%s gap=%s expected=%s", startTime, now, now.Sub(startTime), time.Second)
}
tt := tc.Now()
tc.SetTime(tt.Add(time.Hour))
if tc.Now().Sub(tt) != time.Hour {
t.Errorf("input: %s now=%s gap=%s expected=%s", tt, tc.Now(), tc.Now().Sub(tt), time.Hour)
}
}
func TestFakeClockSleep(t *testing.T) {
startTime := time.Now()
tc := NewFakeClock(startTime)
tc.Sleep(time.Duration(1) * time.Hour)
now := tc.Now()
if now.Sub(startTime) != time.Hour {
t.Errorf("Fake sleep failed, expected time to advance by one hour, instead, its %v", now.Sub(startTime))
}
}
func TestFakeAfter(t *testing.T) {
tc := NewFakeClock(time.Now())
if tc.HasWaiters() {
t.Errorf("unexpected waiter?")
}
oneSec := tc.After(time.Second)
if !tc.HasWaiters() {
t.Errorf("unexpected lack of waiter?")
}
oneOhOneSec := tc.After(time.Second + time.Millisecond)
twoSec := tc.After(2 * time.Second)
select {
case <-oneSec:
t.Errorf("unexpected channel read")
case <-oneOhOneSec:
t.Errorf("unexpected channel read")
case <-twoSec:
t.Errorf("unexpected channel read")
default:
}
tc.Step(999 * time.Millisecond)
select {
case <-oneSec:
t.Errorf("unexpected channel read")
case <-oneOhOneSec:
t.Errorf("unexpected channel read")
case <-twoSec:
t.Errorf("unexpected channel read")
default:
}
tc.Step(time.Millisecond)
select {
case <-oneSec:
// Expected!
case <-oneOhOneSec:
t.Errorf("unexpected channel read")
case <-twoSec:
t.Errorf("unexpected channel read")
default:
t.Errorf("unexpected non-channel read")
}
tc.Step(time.Millisecond)
select {
case <-oneSec:
// should not double-trigger!
t.Errorf("unexpected channel read")
case <-oneOhOneSec:
// Expected!
case <-twoSec:
t.Errorf("unexpected channel read")
default:
t.Errorf("unexpected non-channel read")
}
}
func TestFakeTick(t *testing.T) {
tc := NewFakeClock(time.Now())
if tc.HasWaiters() {
t.Errorf("unexpected waiter?")
}
oneSec := tc.Tick(time.Second)
if !tc.HasWaiters() {
t.Errorf("unexpected lack of waiter?")
}
oneOhOneSec := tc.Tick(time.Second + time.Millisecond)
twoSec := tc.Tick(2 * time.Second)
select {
case <-oneSec:
t.Errorf("unexpected channel read")
case <-oneOhOneSec:
t.Errorf("unexpected channel read")
case <-twoSec:
t.Errorf("unexpected channel read")
default:
}
tc.Step(999 * time.Millisecond) // t=.999
select {
case <-oneSec:
t.Errorf("unexpected channel read")
case <-oneOhOneSec:
t.Errorf("unexpected channel read")
case <-twoSec:
t.Errorf("unexpected channel read")
default:
}
tc.Step(time.Millisecond) // t=1.000
select {
case <-oneSec:
// Expected!
case <-oneOhOneSec:
t.Errorf("unexpected channel read")
case <-twoSec:
t.Errorf("unexpected channel read")
default:
t.Errorf("unexpected non-channel read")
}
tc.Step(time.Millisecond) // t=1.001
select {
case <-oneSec:
// should not double-trigger!
t.Errorf("unexpected channel read")
case <-oneOhOneSec:
// Expected!
case <-twoSec:
t.Errorf("unexpected channel read")
default:
t.Errorf("unexpected non-channel read")
}
tc.Step(time.Second) // t=2.001
tc.Step(time.Second) // t=3.001
tc.Step(time.Second) // t=4.001
tc.Step(time.Second) // t=5.001
// The one second ticker should not accumulate ticks
accumulatedTicks := 0
drained := false
for !drained {
select {
case <-oneSec:
accumulatedTicks++
default:
drained = true
}
}
if accumulatedTicks != 1 {
t.Errorf("unexpected number of accumulated ticks: %d", accumulatedTicks)
}
}

View File

@ -0,0 +1,195 @@
/*
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 flowcontrol
import (
"testing"
"time"
"k8s.io/client-go/pkg/util/clock"
)
func TestSlowBackoff(t *testing.T) {
id := "_idSlow"
tc := clock.NewFakeClock(time.Now())
step := time.Second
maxDuration := 50 * step
b := NewFakeBackOff(step, maxDuration, tc)
cases := []time.Duration{0, 1, 2, 4, 8, 16, 32, 50, 50, 50}
for ix, c := range cases {
tc.Step(step)
w := b.Get(id)
if w != c*step {
t.Errorf("input: '%d': expected %s, got %s", ix, c*step, w)
}
b.Next(id, tc.Now())
}
//Now confirm that the Reset cancels backoff.
b.Next(id, tc.Now())
b.Reset(id)
if b.Get(id) != 0 {
t.Errorf("Reset didn't clear the backoff.")
}
}
func TestBackoffReset(t *testing.T) {
id := "_idReset"
tc := clock.NewFakeClock(time.Now())
step := time.Second
maxDuration := step * 5
b := NewFakeBackOff(step, maxDuration, tc)
startTime := tc.Now()
// get to backoff = maxDuration
for i := 0; i <= int(maxDuration/step); i++ {
tc.Step(step)
b.Next(id, tc.Now())
}
// backoff should be capped at maxDuration
if !b.IsInBackOffSince(id, tc.Now()) {
t.Errorf("expected to be in Backoff got %s", b.Get(id))
}
lastUpdate := tc.Now()
tc.Step(2*maxDuration + step) // time += 11s, 11 > 2*maxDuration
if b.IsInBackOffSince(id, lastUpdate) {
t.Errorf("expected to not be in Backoff after reset (start=%s, now=%s, lastUpdate=%s), got %s", startTime, tc.Now(), lastUpdate, b.Get(id))
}
}
func TestBackoffHightWaterMark(t *testing.T) {
id := "_idHiWaterMark"
tc := clock.NewFakeClock(time.Now())
step := time.Second
maxDuration := 5 * step
b := NewFakeBackOff(step, maxDuration, tc)
// get to backoff = maxDuration
for i := 0; i <= int(maxDuration/step); i++ {
tc.Step(step)
b.Next(id, tc.Now())
}
// backoff high watermark expires after 2*maxDuration
tc.Step(maxDuration + step)
b.Next(id, tc.Now())
if b.Get(id) != maxDuration {
t.Errorf("expected Backoff to stay at high watermark %s got %s", maxDuration, b.Get(id))
}
}
func TestBackoffGC(t *testing.T) {
id := "_idGC"
tc := clock.NewFakeClock(time.Now())
step := time.Second
maxDuration := 5 * step
b := NewFakeBackOff(step, maxDuration, tc)
for i := 0; i <= int(maxDuration/step); i++ {
tc.Step(step)
b.Next(id, tc.Now())
}
lastUpdate := tc.Now()
tc.Step(maxDuration + step)
b.GC()
_, found := b.perItemBackoff[id]
if !found {
t.Errorf("expected GC to skip entry, elapsed time=%s maxDuration=%s", tc.Now().Sub(lastUpdate), maxDuration)
}
tc.Step(maxDuration + step)
b.GC()
r, found := b.perItemBackoff[id]
if found {
t.Errorf("expected GC of entry after %s got entry %v", tc.Now().Sub(lastUpdate), r)
}
}
func TestIsInBackOffSinceUpdate(t *testing.T) {
id := "_idIsInBackOffSinceUpdate"
tc := clock.NewFakeClock(time.Now())
step := time.Second
maxDuration := 10 * step
b := NewFakeBackOff(step, maxDuration, tc)
startTime := tc.Now()
cases := []struct {
tick time.Duration
inBackOff bool
value int
}{
{tick: 0, inBackOff: false, value: 0},
{tick: 1, inBackOff: false, value: 1},
{tick: 2, inBackOff: true, value: 2},
{tick: 3, inBackOff: false, value: 2},
{tick: 4, inBackOff: true, value: 4},
{tick: 5, inBackOff: true, value: 4},
{tick: 6, inBackOff: true, value: 4},
{tick: 7, inBackOff: false, value: 4},
{tick: 8, inBackOff: true, value: 8},
{tick: 9, inBackOff: true, value: 8},
{tick: 10, inBackOff: true, value: 8},
{tick: 11, inBackOff: true, value: 8},
{tick: 12, inBackOff: true, value: 8},
{tick: 13, inBackOff: true, value: 8},
{tick: 14, inBackOff: true, value: 8},
{tick: 15, inBackOff: false, value: 8},
{tick: 16, inBackOff: true, value: 10},
{tick: 17, inBackOff: true, value: 10},
{tick: 18, inBackOff: true, value: 10},
{tick: 19, inBackOff: true, value: 10},
{tick: 20, inBackOff: true, value: 10},
{tick: 21, inBackOff: true, value: 10},
{tick: 22, inBackOff: true, value: 10},
{tick: 23, inBackOff: true, value: 10},
{tick: 24, inBackOff: true, value: 10},
{tick: 25, inBackOff: false, value: 10},
{tick: 26, inBackOff: true, value: 10},
{tick: 27, inBackOff: true, value: 10},
{tick: 28, inBackOff: true, value: 10},
{tick: 29, inBackOff: true, value: 10},
{tick: 30, inBackOff: true, value: 10},
{tick: 31, inBackOff: true, value: 10},
{tick: 32, inBackOff: true, value: 10},
{tick: 33, inBackOff: true, value: 10},
{tick: 34, inBackOff: true, value: 10},
{tick: 35, inBackOff: false, value: 10},
{tick: 56, inBackOff: false, value: 0},
{tick: 57, inBackOff: false, value: 1},
}
for _, c := range cases {
tc.SetTime(startTime.Add(c.tick * step))
if c.inBackOff != b.IsInBackOffSinceUpdate(id, tc.Now()) {
t.Errorf("expected IsInBackOffSinceUpdate %v got %v at tick %s", c.inBackOff, b.IsInBackOffSinceUpdate(id, tc.Now()), c.tick*step)
}
if c.inBackOff && (time.Duration(c.value)*step != b.Get(id)) {
t.Errorf("expected backoff value=%s got %s at tick %s", time.Duration(c.value)*step, b.Get(id), c.tick*step)
}
if !c.inBackOff {
b.Next(id, tc.Now())
}
}
}

View File

@ -0,0 +1,177 @@
/*
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 flowcontrol
import (
"math"
"sync"
"testing"
"time"
)
func TestMultithreadedThrottling(t *testing.T) {
// Bucket with 100QPS and no burst
r := NewTokenBucketRateLimiter(100, 1)
// channel to collect 100 tokens
taken := make(chan bool, 100)
// Set up goroutines to hammer the throttler
startCh := make(chan bool)
endCh := make(chan bool)
for i := 0; i < 10; i++ {
go func() {
// wait for the starting signal
<-startCh
for {
// get a token
r.Accept()
select {
// try to add it to the taken channel
case taken <- true:
continue
// if taken is full, notify and return
default:
endCh <- true
return
}
}
}()
}
// record wall time
startTime := time.Now()
// take the initial capacity so all tokens are the result of refill
r.Accept()
// start the thundering herd
close(startCh)
// wait for the first signal that we collected 100 tokens
<-endCh
// record wall time
endTime := time.Now()
// tolerate a 1% clock change because these things happen
if duration := endTime.Sub(startTime); duration < (time.Second * 99 / 100) {
// We shouldn't be able to get 100 tokens out of the bucket in less than 1 second of wall clock time, no matter what
t.Errorf("Expected it to take at least 1 second to get 100 tokens, took %v", duration)
} else {
t.Logf("Took %v to get 100 tokens", duration)
}
}
func TestBasicThrottle(t *testing.T) {
r := NewTokenBucketRateLimiter(1, 3)
for i := 0; i < 3; i++ {
if !r.TryAccept() {
t.Error("unexpected false accept")
}
}
if r.TryAccept() {
t.Error("unexpected true accept")
}
}
func TestIncrementThrottle(t *testing.T) {
r := NewTokenBucketRateLimiter(1, 1)
if !r.TryAccept() {
t.Error("unexpected false accept")
}
if r.TryAccept() {
t.Error("unexpected true accept")
}
// Allow to refill
time.Sleep(2 * time.Second)
if !r.TryAccept() {
t.Error("unexpected false accept")
}
}
func TestThrottle(t *testing.T) {
r := NewTokenBucketRateLimiter(10, 5)
// Should consume 5 tokens immediately, then
// the remaining 11 should take at least 1 second (0.1s each)
expectedFinish := time.Now().Add(time.Second * 1)
for i := 0; i < 16; i++ {
r.Accept()
}
if time.Now().Before(expectedFinish) {
t.Error("rate limit was not respected, finished too early")
}
}
func TestRateLimiterSaturation(t *testing.T) {
const e = 0.000001
tests := []struct {
capacity int
take int
expectedSaturation float64
}{
{1, 1, 1},
{10, 3, 0.3},
}
for i, tt := range tests {
rl := NewTokenBucketRateLimiter(1, tt.capacity)
for i := 0; i < tt.take; i++ {
rl.Accept()
}
if math.Abs(rl.Saturation()-tt.expectedSaturation) > e {
t.Fatalf("#%d: Saturation rate difference isn't within tolerable range\n want=%f, get=%f",
i, tt.expectedSaturation, rl.Saturation())
}
}
}
func TestAlwaysFake(t *testing.T) {
rl := NewFakeAlwaysRateLimiter()
if !rl.TryAccept() {
t.Error("TryAccept in AlwaysFake should return true.")
}
// If this will block the test will timeout
rl.Accept()
}
func TestNeverFake(t *testing.T) {
rl := NewFakeNeverRateLimiter()
if rl.TryAccept() {
t.Error("TryAccept in NeverFake should return false.")
}
finished := false
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
rl.Accept()
finished = true
wg.Done()
}()
// Wait some time to make sure it never finished.
time.Sleep(time.Second)
if finished {
t.Error("Accept should block forever in NeverFake.")
}
rl.Stop()
wg.Wait()
if !finished {
t.Error("Stop should make Accept unblock in NeverFake.")
}
}

View File

@ -0,0 +1,244 @@
/*
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 integer
import "testing"
func TestIntMax(t *testing.T) {
tests := []struct {
nums []int
expectedMax int
}{
{
nums: []int{-1, 0},
expectedMax: 0,
},
{
nums: []int{-1, -2},
expectedMax: -1,
},
{
nums: []int{0, 1},
expectedMax: 1,
},
{
nums: []int{1, 2},
expectedMax: 2,
},
}
for i, test := range tests {
t.Logf("executing scenario %d", i)
if max := IntMax(test.nums[0], test.nums[1]); max != test.expectedMax {
t.Errorf("expected %v, got %v", test.expectedMax, max)
}
}
}
func TestIntMin(t *testing.T) {
tests := []struct {
nums []int
expectedMin int
}{
{
nums: []int{-1, 0},
expectedMin: -1,
},
{
nums: []int{-1, -2},
expectedMin: -2,
},
{
nums: []int{0, 1},
expectedMin: 0,
},
{
nums: []int{1, 2},
expectedMin: 1,
},
}
for i, test := range tests {
t.Logf("executing scenario %d", i)
if min := IntMin(test.nums[0], test.nums[1]); min != test.expectedMin {
t.Errorf("expected %v, got %v", test.expectedMin, min)
}
}
}
func TestInt32Max(t *testing.T) {
tests := []struct {
nums []int32
expectedMax int32
}{
{
nums: []int32{-1, 0},
expectedMax: 0,
},
{
nums: []int32{-1, -2},
expectedMax: -1,
},
{
nums: []int32{0, 1},
expectedMax: 1,
},
{
nums: []int32{1, 2},
expectedMax: 2,
},
}
for i, test := range tests {
t.Logf("executing scenario %d", i)
if max := Int32Max(test.nums[0], test.nums[1]); max != test.expectedMax {
t.Errorf("expected %v, got %v", test.expectedMax, max)
}
}
}
func TestInt32Min(t *testing.T) {
tests := []struct {
nums []int32
expectedMin int32
}{
{
nums: []int32{-1, 0},
expectedMin: -1,
},
{
nums: []int32{-1, -2},
expectedMin: -2,
},
{
nums: []int32{0, 1},
expectedMin: 0,
},
{
nums: []int32{1, 2},
expectedMin: 1,
},
}
for i, test := range tests {
t.Logf("executing scenario %d", i)
if min := Int32Min(test.nums[0], test.nums[1]); min != test.expectedMin {
t.Errorf("expected %v, got %v", test.expectedMin, min)
}
}
}
func TestInt64Max(t *testing.T) {
tests := []struct {
nums []int64
expectedMax int64
}{
{
nums: []int64{-1, 0},
expectedMax: 0,
},
{
nums: []int64{-1, -2},
expectedMax: -1,
},
{
nums: []int64{0, 1},
expectedMax: 1,
},
{
nums: []int64{1, 2},
expectedMax: 2,
},
}
for i, test := range tests {
t.Logf("executing scenario %d", i)
if max := Int64Max(test.nums[0], test.nums[1]); max != test.expectedMax {
t.Errorf("expected %v, got %v", test.expectedMax, max)
}
}
}
func TestInt64Min(t *testing.T) {
tests := []struct {
nums []int64
expectedMin int64
}{
{
nums: []int64{-1, 0},
expectedMin: -1,
},
{
nums: []int64{-1, -2},
expectedMin: -2,
},
{
nums: []int64{0, 1},
expectedMin: 0,
},
{
nums: []int64{1, 2},
expectedMin: 1,
},
}
for i, test := range tests {
t.Logf("executing scenario %d", i)
if min := Int64Min(test.nums[0], test.nums[1]); min != test.expectedMin {
t.Errorf("expected %v, got %v", test.expectedMin, min)
}
}
}
func TestRoundToInt32(t *testing.T) {
tests := []struct {
num float64
exp int32
}{
{
num: 5.5,
exp: 6,
},
{
num: -3.7,
exp: -4,
},
{
num: 3.49,
exp: 3,
},
{
num: -7.9,
exp: -8,
},
{
num: -4.499999,
exp: -4,
},
{
num: 0,
exp: 0,
},
}
for i, test := range tests {
t.Logf("executing scenario %d", i)
if got := RoundToInt32(test.num); got != test.exp {
t.Errorf("expected %d, got %d", test.exp, got)
}
}
}

View File

@ -17,4 +17,4 @@ limitations under the License.
// package jsonpath is a template engine using jsonpath syntax,
// which can be seen at http://goessner.net/articles/JsonPath/.
// In addition, it has {range} {end} function to iterate list and slice.
package jsonpath
package jsonpath // import "k8s.io/client-go/pkg/util/jsonpath"

View File

@ -0,0 +1,282 @@
/*
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 jsonpath
import (
"bytes"
"encoding/json"
"fmt"
"reflect"
"sort"
"strings"
"testing"
)
type jsonpathTest struct {
name string
template string
input interface{}
expect string
}
func testJSONPath(tests []jsonpathTest, allowMissingKeys bool, t *testing.T) {
for _, test := range tests {
j := New(test.name)
j.AllowMissingKeys(allowMissingKeys)
err := j.Parse(test.template)
if err != nil {
t.Errorf("in %s, parse %s error %v", test.name, test.template, err)
}
buf := new(bytes.Buffer)
err = j.Execute(buf, test.input)
if err != nil {
t.Errorf("in %s, execute error %v", test.name, err)
}
out := buf.String()
if out != test.expect {
t.Errorf(`in %s, expect to get "%s", got "%s"`, test.name, test.expect, out)
}
}
}
// testJSONPathSortOutput test cases related to map, the results may print in random order
func testJSONPathSortOutput(tests []jsonpathTest, t *testing.T) {
for _, test := range tests {
j := New(test.name)
err := j.Parse(test.template)
if err != nil {
t.Errorf("in %s, parse %s error %v", test.name, test.template, err)
}
buf := new(bytes.Buffer)
err = j.Execute(buf, test.input)
if err != nil {
t.Errorf("in %s, execute error %v", test.name, err)
}
out := buf.String()
//since map is visited in random order, we need to sort the results.
sortedOut := strings.Fields(out)
sort.Strings(sortedOut)
sortedExpect := strings.Fields(test.expect)
sort.Strings(sortedExpect)
if !reflect.DeepEqual(sortedOut, sortedExpect) {
t.Errorf(`in %s, expect to get "%s", got "%s"`, test.name, test.expect, out)
}
}
}
func testFailJSONPath(tests []jsonpathTest, t *testing.T) {
for _, test := range tests {
j := New(test.name)
err := j.Parse(test.template)
if err != nil {
t.Errorf("in %s, parse %s error %v", test.name, test.template, err)
}
buf := new(bytes.Buffer)
err = j.Execute(buf, test.input)
var out string
if err == nil {
out = "nil"
} else {
out = err.Error()
}
if out != test.expect {
t.Errorf("in %s, expect to get error %q, got %q", test.name, test.expect, out)
}
}
}
type book struct {
Category string
Author string
Title string
Price float32
}
func (b book) String() string {
return fmt.Sprintf("{Category: %s, Author: %s, Title: %s, Price: %v}", b.Category, b.Author, b.Title, b.Price)
}
type bicycle struct {
Color string
Price float32
}
type empName string
type job string
type store struct {
Book []book
Bicycle bicycle
Name string
Labels map[string]int
Employees map[empName]job
}
func TestStructInput(t *testing.T) {
storeData := store{
Name: "jsonpath",
Book: []book{
{"reference", "Nigel Rees", "Sayings of the Centurey", 8.95},
{"fiction", "Evelyn Waugh", "Sword of Honour", 12.99},
{"fiction", "Herman Melville", "Moby Dick", 8.99},
},
Bicycle: bicycle{"red", 19.95},
Labels: map[string]int{
"engieer": 10,
"web/html": 15,
"k8s-app": 20,
},
Employees: map[empName]job{
"jason": "manager",
"dan": "clerk",
},
}
storeTests := []jsonpathTest{
{"plain", "hello jsonpath", nil, "hello jsonpath"},
{"recursive", "{..}", []int{1, 2, 3}, "[1 2 3]"},
{"filter", "{[?(@<5)]}", []int{2, 6, 3, 7}, "2 3"},
{"quote", `{"{"}`, nil, "{"},
{"union", "{[1,3,4]}", []int{0, 1, 2, 3, 4}, "1 3 4"},
{"array", "{[0:2]}", []string{"Monday", "Tudesday"}, "Monday Tudesday"},
{"variable", "hello {.Name}", storeData, "hello jsonpath"},
{"dict/", "{$.Labels.web/html}", storeData, "15"},
{"dict/", "{$.Employees.jason}", storeData, "manager"},
{"dict/", "{$.Employees.dan}", storeData, "clerk"},
{"dict-", "{.Labels.k8s-app}", storeData, "20"},
{"nest", "{.Bicycle.Color}", storeData, "red"},
{"allarray", "{.Book[*].Author}", storeData, "Nigel Rees Evelyn Waugh Herman Melville"},
{"allfileds", "{.Bicycle.*}", storeData, "red 19.95"},
{"recurfileds", "{..Price}", storeData, "8.95 12.99 8.99 19.95"},
{"lastarray", "{.Book[-1:]}", storeData,
"{Category: fiction, Author: Herman Melville, Title: Moby Dick, Price: 8.99}"},
{"recurarray", "{..Book[2]}", storeData,
"{Category: fiction, Author: Herman Melville, Title: Moby Dick, Price: 8.99}"},
}
testJSONPath(storeTests, false, t)
missingKeyTests := []jsonpathTest{
{"nonexistent field", "{.hello}", storeData, ""},
}
testJSONPath(missingKeyTests, true, t)
failStoreTests := []jsonpathTest{
{"invalid identifier", "{hello}", storeData, "unrecognized identifier hello"},
{"nonexistent field", "{.hello}", storeData, "hello is not found"},
{"invalid array", "{.Labels[0]}", storeData, "map[string]int is not array or slice"},
{"invalid filter operator", "{.Book[?(@.Price<>10)]}", storeData, "unrecognized filter operator <>"},
{"redundent end", "{range .Labels.*}{@}{end}{end}", storeData, "not in range, nothing to end"},
}
testFailJSONPath(failStoreTests, t)
}
func TestJSONInput(t *testing.T) {
var pointsJSON = []byte(`[
{"id": "i1", "x":4, "y":-5},
{"id": "i2", "x":-2, "y":-5, "z":1},
{"id": "i3", "x": 8, "y": 3 },
{"id": "i4", "x": -6, "y": -1 },
{"id": "i5", "x": 0, "y": 2, "z": 1 },
{"id": "i6", "x": 1, "y": 4 }
]`)
var pointsData interface{}
err := json.Unmarshal(pointsJSON, &pointsData)
if err != nil {
t.Error(err)
}
pointsTests := []jsonpathTest{
{"exists filter", "{[?(@.z)].id}", pointsData, "i2 i5"},
{"bracket key", "{[0]['id']}", pointsData, "i1"},
}
testJSONPath(pointsTests, false, t)
}
// TestKubernetes tests some use cases from kubernetes
func TestKubernetes(t *testing.T) {
var input = []byte(`{
"kind": "List",
"items":[
{
"kind":"None",
"metadata":{
"name":"127.0.0.1",
"labels":{
"kubernetes.io/hostname":"127.0.0.1"
}
},
"status":{
"capacity":{"cpu":"4"},
"addresses":[{"type": "LegacyHostIP", "address":"127.0.0.1"}]
}
},
{
"kind":"None",
"metadata":{
"name":"127.0.0.2",
"labels":{
"kubernetes.io/hostname":"127.0.0.2"
}
},
"status":{
"capacity":{"cpu":"8"},
"addresses":[
{"type": "LegacyHostIP", "address":"127.0.0.2"},
{"type": "another", "address":"127.0.0.3"}
]
}
}
],
"users":[
{
"name": "myself",
"user": {}
},
{
"name": "e2e",
"user": {"username": "admin", "password": "secret"}
}
]
}`)
var nodesData interface{}
err := json.Unmarshal(input, &nodesData)
if err != nil {
t.Error(err)
}
nodesTests := []jsonpathTest{
{"range item", `{range .items[*]}{.metadata.name}, {end}{.kind}`, nodesData, "127.0.0.1, 127.0.0.2, List"},
{"range item with quote", `{range .items[*]}{.metadata.name}{"\t"}{end}`, nodesData, "127.0.0.1\t127.0.0.2\t"},
{"range addresss", `{.items[*].status.addresses[*].address}`, nodesData,
"127.0.0.1 127.0.0.2 127.0.0.3"},
{"double range", `{range .items[*]}{range .status.addresses[*]}{.address}, {end}{end}`, nodesData,
"127.0.0.1, 127.0.0.2, 127.0.0.3, "},
{"item name", `{.items[*].metadata.name}`, nodesData, "127.0.0.1 127.0.0.2"},
{"union nodes capacity", `{.items[*]['metadata.name', 'status.capacity']}`, nodesData,
"127.0.0.1 127.0.0.2 map[cpu:4] map[cpu:8]"},
{"range nodes capacity", `{range .items[*]}[{.metadata.name}, {.status.capacity}] {end}`, nodesData,
"[127.0.0.1, map[cpu:4]] [127.0.0.2, map[cpu:8]] "},
{"user password", `{.users[?(@.name=="e2e")].user.password}`, &nodesData, "secret"},
{"hostname", `{.items[0].metadata.labels.kubernetes\.io/hostname}`, &nodesData, "127.0.0.1"},
{"hostname filter", `{.items[?(@.metadata.labels.kubernetes\.io/hostname=="127.0.0.1")].kind}`, &nodesData, "None"},
}
testJSONPath(nodesTests, false, t)
randomPrintOrderTests := []jsonpathTest{
{"recursive name", "{..name}", nodesData, `127.0.0.1 127.0.0.2 myself e2e`},
}
testJSONPathSortOutput(randomPrintOrderTests, t)
}

View File

@ -0,0 +1,136 @@
/*
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 jsonpath
import (
"testing"
)
type parserTest struct {
name string
text string
nodes []Node
shouldError bool
}
var parserTests = []parserTest{
{"plain", `hello jsonpath`, []Node{newText("hello jsonpath")}, false},
{"variable", `hello {.jsonpath}`,
[]Node{newText("hello "), newList(), newField("jsonpath")}, false},
{"arrayfiled", `hello {['jsonpath']}`,
[]Node{newText("hello "), newList(), newField("jsonpath")}, false},
{"quote", `{"{"}`, []Node{newList(), newText("{")}, false},
{"array", `{[1:3]}`, []Node{newList(),
newArray([3]ParamsEntry{{1, true}, {3, true}, {0, false}})}, false},
{"allarray", `{.book[*].author}`,
[]Node{newList(), newField("book"),
newArray([3]ParamsEntry{{0, false}, {0, false}, {0, false}}), newField("author")}, false},
{"wildcard", `{.bicycle.*}`,
[]Node{newList(), newField("bicycle"), newWildcard()}, false},
{"filter", `{[?(@.price<3)]}`,
[]Node{newList(), newFilter(newList(), newList(), "<"),
newList(), newField("price"), newList(), newInt(3)}, false},
{"recursive", `{..}`, []Node{newList(), newRecursive()}, false},
{"recurField", `{..price}`,
[]Node{newList(), newRecursive(), newField("price")}, false},
{"arraydict", `{['book.price']}`, []Node{newList(),
newField("book"), newField("price"),
}, false},
{"union", `{['bicycle.price', 3, 'book.price']}`, []Node{newList(), newUnion([]*ListNode{}),
newList(), newField("bicycle"), newField("price"),
newList(), newArray([3]ParamsEntry{{3, true}, {4, true}, {0, false}}),
newList(), newField("book"), newField("price"),
}, false},
{"range", `{range .items}{.name},{end}`, []Node{
newList(), newIdentifier("range"), newField("items"),
newList(), newField("name"), newText(","),
newList(), newIdentifier("end"),
}, false},
{"malformat input", `{\\\}`, []Node{}, true},
}
func collectNode(nodes []Node, cur Node) []Node {
nodes = append(nodes, cur)
switch cur.Type() {
case NodeList:
for _, node := range cur.(*ListNode).Nodes {
nodes = collectNode(nodes, node)
}
case NodeFilter:
nodes = collectNode(nodes, cur.(*FilterNode).Left)
nodes = collectNode(nodes, cur.(*FilterNode).Right)
case NodeUnion:
for _, node := range cur.(*UnionNode).Nodes {
nodes = collectNode(nodes, node)
}
}
return nodes
}
func TestParser(t *testing.T) {
for _, test := range parserTests {
parser, err := Parse(test.name, test.text)
if test.shouldError {
if err == nil {
t.Errorf("unexpected non-error when parsing %s", test.name)
}
continue
}
if err != nil {
t.Errorf("parse %s error %v", test.name, err)
}
result := collectNode([]Node{}, parser.Root)[1:]
if len(result) != len(test.nodes) {
t.Errorf("in %s, expect to get %d nodes, got %d nodes", test.name, len(test.nodes), len(result))
t.Error(result)
}
for i, expect := range test.nodes {
if result[i].String() != expect.String() {
t.Errorf("in %s, %dth node, expect %v, got %v", test.name, i, expect, result[i])
}
}
}
}
type failParserTest struct {
name string
text string
err string
}
func TestFailParser(t *testing.T) {
failParserTests := []failParserTest{
{"unclosed action", "{.hello", "unclosed action"},
{"unrecognized character", "{*}", "unrecognized character in action: U+002A '*'"},
{"invalid number", "{+12.3.0}", "cannot parse number +12.3.0"},
{"unterminated array", "{[1}", "unterminated array"},
{"invalid index", "{[::-1]}", "invalid array index ::-1"},
{"unterminated filter", "{[?(.price]}", "unterminated filter"},
}
for _, test := range failParserTests {
_, err := Parse(test.name, test.text)
var out string
if err == nil {
out = "nil"
} else {
out = err.Error()
}
if out != test.err {
t.Errorf("in %s, expect to get error %v, got %v", test.name, test.err, out)
}
}
}

View File

@ -48,6 +48,13 @@ const (
deleteFromPrimitiveListDirectivePrefix = "$deleteFromPrimitiveList"
)
// JSONMap is a representations of JSON object encoded as map[string]interface{}
// where the children can be either map[string]interface{}, []interface{} or
// primitive type).
// Operating on JSONMap representation is much faster as it doesn't require any
// json marshaling and/or unmarshaling operations.
type JSONMap map[string]interface{}
// IsPreconditionFailed returns true if the provided error indicates
// a precondition failed.
func IsPreconditionFailed(err error) bool {
@ -136,11 +143,6 @@ func RequireMetadataKeyUnchanged(key string) PreconditionFunc {
}
}
// Deprecated: Use the synonym CreateTwoWayMergePatch, instead.
func CreateStrategicMergePatch(original, modified []byte, dataStruct interface{}) ([]byte, error) {
return CreateTwoWayMergePatch(original, modified, dataStruct)
}
// CreateTwoWayMergePatch creates a patch that can be passed to StrategicMergePatch from an original
// document and a modified document, which are passed to the method as json encoded content. It will
// return a patch that yields the modified document when applied to the original document, or an error
@ -160,12 +162,24 @@ func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, f
}
}
patchMap, err := CreateTwoWayMergeMapPatch(originalMap, modifiedMap, dataStruct, fns...)
if err != nil {
return nil, err
}
return json.Marshal(patchMap)
}
// CreateTwoWayMergeMapPatch creates a patch from an original and modified JSON objects,
// encoded JSONMap.
// The serialized version of the map can then be passed to StrategicMergeMapPatch.
func CreateTwoWayMergeMapPatch(original, modified JSONMap, dataStruct interface{}, fns ...PreconditionFunc) (JSONMap, error) {
t, err := getTagStructType(dataStruct)
if err != nil {
return nil, err
}
patchMap, err := diffMaps(originalMap, modifiedMap, t, false, false)
patchMap, err := diffMaps(original, modified, t, false, false)
if err != nil {
return nil, err
}
@ -177,7 +191,7 @@ func CreateTwoWayMergePatch(original, modified []byte, dataStruct interface{}, f
}
}
return json.Marshal(patchMap)
return patchMap, nil
}
// Returns a (recursive) strategic merge patch that yields modified when applied to original.
@ -494,12 +508,6 @@ loopB:
return patch, nil
}
// Deprecated: StrategicMergePatchData is deprecated. Use the synonym StrategicMergePatch,
// instead, which follows the naming convention of evanphx/json-patch.
func StrategicMergePatchData(original, patch []byte, dataStruct interface{}) ([]byte, error) {
return StrategicMergePatch(original, patch, dataStruct)
}
// StrategicMergePatch applies a strategic merge patch. The patch and the original document
// must be json encoded content. A patch can be created from an original and a modified document
// by calling CreateStrategicMergePatch.
@ -524,12 +532,7 @@ func StrategicMergePatch(original, patch []byte, dataStruct interface{}) ([]byte
return nil, errBadJSONDoc
}
t, err := getTagStructType(dataStruct)
if err != nil {
return nil, err
}
result, err := mergeMap(originalMap, patchMap, t, true)
result, err := StrategicMergeMapPatch(originalMap, patchMap, dataStruct)
if err != nil {
return nil, err
}
@ -537,6 +540,17 @@ func StrategicMergePatch(original, patch []byte, dataStruct interface{}) ([]byte
return json.Marshal(result)
}
// StrategicMergePatch applies a strategic merge patch. The original and patch documents
// must be JSONMap. A patch can be created from an original and modified document by
// calling CreateTwoWayMergeMapPatch.
func StrategicMergeMapPatch(original, patch JSONMap, dataStruct interface{}) (JSONMap, error) {
t, err := getTagStructType(dataStruct)
if err != nil {
return nil, err
}
return mergeMap(original, patch, t, true)
}
func getTagStructType(dataStruct interface{}) (reflect.Type, error) {
if dataStruct == nil {
return nil, fmt.Errorf(errBadArgTypeFmt, "struct", "nil")

View File

@ -0,0 +1,180 @@
/*
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 testing
import (
"bytes"
"net/http"
"net/http/httptest"
"testing"
)
func TestFakeHandlerPath(t *testing.T) {
handler := FakeHandler{StatusCode: http.StatusOK}
server := httptest.NewServer(&handler)
defer server.Close()
method := "GET"
path := "/foo/bar"
body := "somebody"
req, err := http.NewRequest(method, server.URL+path, bytes.NewBufferString(body))
if err != nil {
t.Errorf("unexpected error: %v", err)
}
client := http.Client{}
_, err = client.Do(req)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
handler.ValidateRequest(t, path, method, &body)
}
func TestFakeHandlerPathNoBody(t *testing.T) {
handler := FakeHandler{StatusCode: http.StatusOK}
server := httptest.NewServer(&handler)
defer server.Close()
method := "GET"
path := "/foo/bar"
req, err := http.NewRequest(method, server.URL+path, nil)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
client := http.Client{}
_, err = client.Do(req)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
handler.ValidateRequest(t, path, method, nil)
}
type fakeError struct {
errors []string
}
func (f *fakeError) Errorf(format string, args ...interface{}) {
f.errors = append(f.errors, format)
}
func (f *fakeError) Logf(format string, args ...interface{}) {}
func TestFakeHandlerWrongPath(t *testing.T) {
handler := FakeHandler{StatusCode: http.StatusOK}
server := httptest.NewServer(&handler)
defer server.Close()
method := "GET"
path := "/foo/bar"
fakeT := fakeError{}
req, err := http.NewRequest(method, server.URL+"/foo/baz", nil)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
client := http.Client{}
_, err = client.Do(req)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
handler.ValidateRequest(&fakeT, path, method, nil)
if len(fakeT.errors) != 1 {
t.Errorf("Unexpected error set: %#v", fakeT.errors)
}
}
func TestFakeHandlerWrongMethod(t *testing.T) {
handler := FakeHandler{StatusCode: http.StatusOK}
server := httptest.NewServer(&handler)
defer server.Close()
method := "GET"
path := "/foo/bar"
fakeT := fakeError{}
req, err := http.NewRequest("PUT", server.URL+path, nil)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
client := http.Client{}
_, err = client.Do(req)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
handler.ValidateRequest(&fakeT, path, method, nil)
if len(fakeT.errors) != 1 {
t.Errorf("Unexpected error set: %#v", fakeT.errors)
}
}
func TestFakeHandlerWrongBody(t *testing.T) {
handler := FakeHandler{StatusCode: http.StatusOK}
server := httptest.NewServer(&handler)
defer server.Close()
method := "GET"
path := "/foo/bar"
body := "somebody"
fakeT := fakeError{}
req, err := http.NewRequest(method, server.URL+path, bytes.NewBufferString(body))
if err != nil {
t.Errorf("unexpected error: %v", err)
}
client := http.Client{}
_, err = client.Do(req)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
otherbody := "otherbody"
handler.ValidateRequest(&fakeT, path, method, &otherbody)
if len(fakeT.errors) != 1 {
t.Errorf("Unexpected error set: %#v", fakeT.errors)
}
}
func TestFakeHandlerNilBody(t *testing.T) {
handler := FakeHandler{StatusCode: http.StatusOK}
server := httptest.NewServer(&handler)
defer server.Close()
method := "GET"
path := "/foo/bar"
body := "somebody"
fakeT := fakeError{}
req, err := http.NewRequest(method, server.URL+path, nil)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
client := http.Client{}
_, err = client.Do(req)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
handler.ValidateRequest(&fakeT, path, method, &body)
if len(fakeT.errors) != 1 {
t.Errorf("Unexpected error set: %#v", fakeT.errors)
}
}

View File

@ -32,11 +32,11 @@ import (
"golang.org/x/oauth2/google"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/pkg/util/jsonpath"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
func init() {
if err := rest.RegisterAuthProviderPlugin("gcp", newGCPAuthProvider); err != nil {
if err := restclient.RegisterAuthProviderPlugin("gcp", newGCPAuthProvider); err != nil {
glog.Fatalf("Failed to register gcp auth plugin: %v", err)
}
}
@ -85,10 +85,10 @@ func init() {
//
type gcpAuthProvider struct {
tokenSource oauth2.TokenSource
persister rest.AuthProviderConfigPersister
persister restclient.AuthProviderConfigPersister
}
func newGCPAuthProvider(_ string, gcpConfig map[string]string, persister rest.AuthProviderConfigPersister) (rest.AuthProvider, error) {
func newGCPAuthProvider(_ string, gcpConfig map[string]string, persister restclient.AuthProviderConfigPersister) (restclient.AuthProvider, error) {
cmd, useCmd := gcpConfig["cmd-path"]
var ts oauth2.TokenSource
var err error
@ -121,11 +121,11 @@ type cachedTokenSource struct {
source oauth2.TokenSource
accessToken string
expiry time.Time
persister rest.AuthProviderConfigPersister
persister restclient.AuthProviderConfigPersister
cache map[string]string
}
func newCachedTokenSource(accessToken, expiry string, persister rest.AuthProviderConfigPersister, ts oauth2.TokenSource, cache map[string]string) (*cachedTokenSource, error) {
func newCachedTokenSource(accessToken, expiry string, persister restclient.AuthProviderConfigPersister, ts oauth2.TokenSource, cache map[string]string) (*cachedTokenSource, error) {
var expiryTime time.Time
if parsedTime, err := time.Parse(time.RFC3339Nano, expiry); err == nil {
expiryTime = parsedTime

View File

@ -30,7 +30,7 @@ import (
"github.com/coreos/go-oidc/oidc"
"github.com/golang/glog"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
const (
@ -45,7 +45,7 @@ const (
)
func init() {
if err := rest.RegisterAuthProviderPlugin("oidc", newOIDCAuthProvider); err != nil {
if err := restclient.RegisterAuthProviderPlugin("oidc", newOIDCAuthProvider); err != nil {
glog.Fatalf("Failed to register oidc auth plugin: %v", err)
}
}
@ -106,7 +106,7 @@ func (c *clientCache) setClient(issuer, clientID, clientSecret string, client *o
return client
}
func newOIDCAuthProvider(_ string, cfg map[string]string, persister rest.AuthProviderConfigPersister) (rest.AuthProvider, error) {
func newOIDCAuthProvider(_ string, cfg map[string]string, persister restclient.AuthProviderConfigPersister) (restclient.AuthProvider, error) {
issuer := cfg[cfgIssuerUrl]
if issuer == "" {
return nil, fmt.Errorf("Must provide %s", cfgIssuerUrl)
@ -136,14 +136,14 @@ func newOIDCAuthProvider(_ string, cfg map[string]string, persister rest.AuthPro
}
}
clientConfig := rest.Config{
TLSClientConfig: rest.TLSClientConfig{
clientConfig := restclient.Config{
TLSClientConfig: restclient.TLSClientConfig{
CAFile: cfg[cfgCertificateAuthority],
CAData: certAuthData,
},
}
trans, err := rest.TransportFor(&clientConfig)
trans, err := restclient.TransportFor(&clientConfig)
if err != nil {
return nil, err
}
@ -191,7 +191,7 @@ type oidcAuthProvider struct {
// the RoundTripper only trigger a single refresh request.
mu sync.Mutex
cfg map[string]string
persister rest.AuthProviderConfigPersister
persister restclient.AuthProviderConfigPersister
}
func (p *oidcAuthProvider) WrapTransport(rt http.RoundTripper) http.RoundTripper {

View File

@ -30,7 +30,7 @@ import (
"github.com/coreos/go-oidc/key"
"github.com/coreos/go-oidc/oauth2"
oidctesting "k8s.io/client-go/plugin/pkg/auth/authenticator/token/oidc/testing"
oidctesting "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/oidc/testing"
)
func clearCache() {

View File

@ -28,7 +28,7 @@ import (
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/testapi"
"k8s.io/client-go/pkg/util/flowcontrol"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
func CreateHTTPClient(roundTripper func(*http.Request) (*http.Response, error)) *http.Client {
@ -54,27 +54,27 @@ type RESTClient struct {
Err error
}
func (c *RESTClient) Get() *rest.Request {
func (c *RESTClient) Get() *restclient.Request {
return c.request("GET")
}
func (c *RESTClient) Put() *rest.Request {
func (c *RESTClient) Put() *restclient.Request {
return c.request("PUT")
}
func (c *RESTClient) Patch(_ types.PatchType) *rest.Request {
func (c *RESTClient) Patch(_ types.PatchType) *restclient.Request {
return c.request("PATCH")
}
func (c *RESTClient) Post() *rest.Request {
func (c *RESTClient) Post() *restclient.Request {
return c.request("POST")
}
func (c *RESTClient) Delete() *rest.Request {
func (c *RESTClient) Delete() *restclient.Request {
return c.request("DELETE")
}
func (c *RESTClient) Verb(verb string) *rest.Request {
func (c *RESTClient) Verb(verb string) *restclient.Request {
return c.request(verb)
}
@ -86,8 +86,8 @@ func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter {
return nil
}
func (c *RESTClient) request(verb string) *rest.Request {
config := rest.ContentConfig{
func (c *RESTClient) request(verb string) *restclient.Request {
config := restclient.ContentConfig{
ContentType: runtime.ContentTypeJSON,
GroupVersion: &api.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: c.NegotiatedSerializer,
@ -104,7 +104,7 @@ func (c *RESTClient) request(verb string) *rest.Request {
Version: runtime.APIVersionInternal,
}
internalVersion.Version = runtime.APIVersionInternal
serializers := rest.Serializers{
serializers := restclient.Serializers{
Encoder: ns.EncoderForVersion(info.Serializer, api.Registry.GroupOrDie(api.GroupName).GroupVersion),
Decoder: ns.DecoderToVersion(info.Serializer, internalVersion),
}
@ -112,7 +112,7 @@ func (c *RESTClient) request(verb string) *rest.Request {
serializers.StreamingSerializer = info.StreamSerializer.Serializer
serializers.Framer = info.StreamSerializer.Framer
}
return rest.NewRequest(c, verb, &url.URL{Host: "localhost"}, "", config, serializers, nil, nil)
return restclient.NewRequest(c, verb, &url.URL{Host: "localhost"}, "", config, serializers, nil, nil)
}
func (c *RESTClient) Do(req *http.Request) (*http.Response, error) {

View File

@ -35,6 +35,7 @@ import (
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
@ -43,8 +44,6 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/pkg/api/v1"
pathvalidation "k8s.io/client-go/pkg/api/validation/path"
"k8s.io/client-go/pkg/fields"
"k8s.io/client-go/pkg/util/flowcontrol"
restclientwatch "k8s.io/client-go/rest/watch"
"k8s.io/client-go/tools/metrics"
@ -179,7 +178,7 @@ func (r *Request) Resource(resource string) *Request {
r.err = fmt.Errorf("resource already set to %q, cannot change to %q", r.resource, resource)
return r
}
if msgs := pathvalidation.IsValidPathSegmentName(resource); len(msgs) != 0 {
if msgs := IsValidPathSegmentName(resource); len(msgs) != 0 {
r.err = fmt.Errorf("invalid resource %q: %v", resource, msgs)
return r
}
@ -199,7 +198,7 @@ func (r *Request) SubResource(subresources ...string) *Request {
return r
}
for _, s := range subresources {
if msgs := pathvalidation.IsValidPathSegmentName(s); len(msgs) != 0 {
if msgs := IsValidPathSegmentName(s); len(msgs) != 0 {
r.err = fmt.Errorf("invalid subresource %q: %v", s, msgs)
return r
}
@ -221,7 +220,7 @@ func (r *Request) Name(resourceName string) *Request {
r.err = fmt.Errorf("resource name already set to %q, cannot change to %q", r.resourceName, resourceName)
return r
}
if msgs := pathvalidation.IsValidPathSegmentName(resourceName); len(msgs) != 0 {
if msgs := IsValidPathSegmentName(resourceName); len(msgs) != 0 {
r.err = fmt.Errorf("invalid resource name %q: %v", resourceName, msgs)
return r
}
@ -238,7 +237,7 @@ func (r *Request) Namespace(namespace string) *Request {
r.err = fmt.Errorf("namespace already set to %q, cannot change to %q", r.namespace, namespace)
return r
}
if msgs := pathvalidation.IsValidPathSegmentName(namespace); len(msgs) != 0 {
if msgs := IsValidPathSegmentName(namespace); len(msgs) != 0 {
r.err = fmt.Errorf("invalid namespace %q: %v", namespace, msgs)
return r
}
@ -760,10 +759,11 @@ func (r *Request) Stream() (io.ReadCloser, error) {
defer resp.Body.Close()
result := r.transformResponse(resp, req)
if result.err != nil {
return nil, result.err
err := result.Error()
if err == nil {
err = fmt.Errorf("%d while accessing %v: %s", result.statusCode, url, string(result.body))
}
return nil, fmt.Errorf("%d while accessing %v: %s", result.statusCode, url, string(result.body))
return nil, err
}
}
@ -1197,3 +1197,49 @@ func (r Result) Error() error {
}
return r.err
}
// 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)
}
}

View File

@ -868,6 +868,7 @@ func TestRequestStream(t *testing.T) {
testCases := []struct {
Request *Request
Err bool
ErrFn func(error) bool
}{
{
Request: &Request{err: errors.New("bail")},
@ -903,6 +904,26 @@ func TestRequestStream(t *testing.T) {
},
Err: true,
},
{
Request: &Request{
client: clientFunc(func(req *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: http.StatusBadRequest,
Body: ioutil.NopCloser(bytes.NewReader([]byte(`{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"a container name must be specified for pod kube-dns-v20-mz5cv, choose one of: [kubedns dnsmasq healthz]","reason":"BadRequest","code":400}`))),
}, nil
}),
content: defaultContentConfig(),
serializers: defaultSerializers(),
baseURL: &url.URL{},
},
Err: true,
ErrFn: func(err error) bool {
if err.Error() == "a container name must be specified for pod kube-dns-v20-mz5cv, choose one of: [kubedns dnsmasq healthz]" {
return true
}
return false
},
},
}
for i, testCase := range testCases {
testCase.Request.backoffMgr = &NoBackoff{}
@ -914,6 +935,12 @@ func TestRequestStream(t *testing.T) {
if hasErr && body != nil {
t.Errorf("%d: body should be nil when error is returned", i)
}
if hasErr {
if testCase.ErrFn != nil && !testCase.ErrFn(err) {
t.Errorf("unexpected error: %v", err)
}
}
}
}

View File

@ -21,12 +21,12 @@ import (
"path"
"strings"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/fields"
)
func NewRootGetAction(resource schema.GroupVersionResource, name string) GetActionImpl {

View File

@ -26,7 +26,7 @@ import (
"k8s.io/apimachinery/pkg/version"
"k8s.io/apimachinery/pkg/watch"
kubeversion "k8s.io/client-go/pkg/version"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
// Fake implements client.Interface. Meant to be embedded into a struct to get
@ -77,7 +77,7 @@ type ProxyReactor interface {
Handles(action Action) bool
// React handles a watch action and returns results. It may choose to
// delegate by indicating handled=false.
React(action Action) (handled bool, ret rest.ResponseWrapper, err error)
React(action Action) (handled bool, ret restclient.ResponseWrapper, err error)
}
// ReactionFunc is a function that returns an object or error for a given
@ -95,7 +95,7 @@ type WatchReactionFunc func(action Action) (handled bool, ret watch.Interface, e
// ProxyReactionFunc is a function that returns a ResponseWrapper interface
// for a given Action. If "handled" is false, then the test client will
// ignore the results and continue to the next ProxyReactionFunc.
type ProxyReactionFunc func(action Action) (handled bool, ret rest.ResponseWrapper, err error)
type ProxyReactionFunc func(action Action) (handled bool, ret restclient.ResponseWrapper, err error)
// AddReactor appends a reactor to the end of the chain.
func (c *Fake) AddReactor(verb, resource string, reaction ReactionFunc) {
@ -176,7 +176,7 @@ func (c *Fake) InvokesWatch(action Action) (watch.Interface, error) {
// InvokesProxy records the provided Action and then invokes the ReactionFunc
// that handles the action if one exists.
func (c *Fake) InvokesProxy(action Action) rest.ResponseWrapper {
func (c *Fake) InvokesProxy(action Action) restclient.ResponseWrapper {
c.Lock()
defer c.Unlock()

View File

@ -27,7 +27,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
// ObjectTracker keeps track of objects. It is intended to be used to
@ -511,6 +511,6 @@ func (r *SimpleProxyReactor) Handles(action Action) bool {
return true
}
func (r *SimpleProxyReactor) React(action Action) (bool, rest.ResponseWrapper, error) {
func (r *SimpleProxyReactor) React(action Action) (bool, restclient.ResponseWrapper, error) {
return r.Reaction(action)
}

View File

@ -68,7 +68,7 @@ import (
"io/ioutil"
"os"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
// Info holds Kubernetes API authorization config. It is intended
@ -104,8 +104,8 @@ func LoadFromFile(path string) (*Info, error) {
// MergeWithConfig returns a copy of a client.Config with values from the Info.
// The fields of client.Config with a corresponding field in the Info are set
// with the value from the Info.
func (info Info) MergeWithConfig(c rest.Config) (rest.Config, error) {
var config rest.Config = c
func (info Info) MergeWithConfig(c restclient.Config) (restclient.Config, error) {
var config restclient.Config = c
config.Username = info.User
config.Password = info.Password
config.CAFile = info.CAFile

View File

@ -20,12 +20,12 @@ import (
"time"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/fields"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
// ListerWatcher is any object that knows how to perform an initial list and start a watch on a resource.
@ -53,7 +53,7 @@ type ListWatch struct {
// Getter interface knows how to access Get method from RESTClient.
type Getter interface {
Get() *rest.Request
Get() *restclient.Request
}
// NewListWatchFromClient creates a new ListWatch from the specified client, resource, namespace and field selector.

View File

@ -28,7 +28,7 @@ import (
"github.com/imdario/mergo"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
clientauth "k8s.io/client-go/tools/auth"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)
@ -58,7 +58,7 @@ type ClientConfig interface {
// RawConfig returns the merged result of all overrides
RawConfig() (clientcmdapi.Config, error)
// ClientConfig returns a complete client config
ClientConfig() (*rest.Config, error)
ClientConfig() (*restclient.Config, error)
// Namespace returns the namespace resulting from the merged
// result of all overrides and a boolean indicating if it was
// overridden
@ -67,7 +67,7 @@ type ClientConfig interface {
ConfigAccess() ConfigAccess
}
type PersistAuthProviderConfigForUser func(user string) rest.AuthProviderConfigPersister
type PersistAuthProviderConfigForUser func(user string) restclient.AuthProviderConfigPersister
type promptedCredentials struct {
username string
@ -105,7 +105,7 @@ func (config *DirectClientConfig) RawConfig() (clientcmdapi.Config, error) {
}
// ClientConfig implements ClientConfig
func (config *DirectClientConfig) ClientConfig() (*rest.Config, error) {
func (config *DirectClientConfig) ClientConfig() (*restclient.Config, error) {
// check that getAuthInfo, getContext, and getCluster do not return an error.
// Do this before checking if the curent config is usable in the event that an
// AuthInfo, Context, or Cluster config with user-defined names are not found.
@ -129,7 +129,7 @@ func (config *DirectClientConfig) ClientConfig() (*rest.Config, error) {
return nil, err
}
clientConfig := &rest.Config{}
clientConfig := &restclient.Config{}
clientConfig.Host = configClusterInfo.Server
if len(config.overrides.Timeout) > 0 {
@ -146,17 +146,17 @@ func (config *DirectClientConfig) ClientConfig() (*rest.Config, error) {
clientConfig.Host = u.String()
}
if len(configAuthInfo.Impersonate) > 0 {
clientConfig.Impersonate = rest.ImpersonationConfig{UserName: configAuthInfo.Impersonate}
clientConfig.Impersonate = restclient.ImpersonationConfig{UserName: configAuthInfo.Impersonate}
}
// only try to read the auth information if we are secure
if rest.IsConfigTransportTLS(*clientConfig) {
if restclient.IsConfigTransportTLS(*clientConfig) {
var err error
// mergo is a first write wins for map value and a last writing wins for interface values
// NOTE: This behavior changed with https://github.com/imdario/mergo/commit/d304790b2ed594794496464fadd89d2bb266600a.
// Our mergo.Merge version is older than this change.
var persister rest.AuthProviderConfigPersister
var persister restclient.AuthProviderConfigPersister
if config.configAccess != nil {
authInfoName, _ := config.getAuthInfoName()
persister = PersisterForUser(config.configAccess, authInfoName)
@ -183,11 +183,11 @@ func (config *DirectClientConfig) ClientConfig() (*rest.Config, error) {
// 1. configClusterInfo (the final result of command line flags and merged .kubeconfig files)
// 2. configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority)
// 3. load the ~/.kubernetes_auth file as a default
func getServerIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, configClusterInfo clientcmdapi.Cluster) (*rest.Config, error) {
mergedConfig := &rest.Config{}
func getServerIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, configClusterInfo clientcmdapi.Cluster) (*restclient.Config, error) {
mergedConfig := &restclient.Config{}
// configClusterInfo holds the information identify the server provided by .kubeconfig
configClientConfig := &rest.Config{}
configClientConfig := &restclient.Config{}
configClientConfig.CAFile = configClusterInfo.CertificateAuthority
configClientConfig.CAData = configClusterInfo.CertificateAuthorityData
configClientConfig.Insecure = configClusterInfo.InsecureSkipTLSVerify
@ -203,8 +203,8 @@ func getServerIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo,
// 2. configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority)
// 3. if there is not enough information to idenfity the user, load try the ~/.kubernetes_auth file
// 4. if there is not enough information to identify the user, prompt if possible
func (config *DirectClientConfig) getUserIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, fallbackReader io.Reader, persistAuthConfig rest.AuthProviderConfigPersister) (*rest.Config, error) {
mergedConfig := &rest.Config{}
func (config *DirectClientConfig) getUserIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, fallbackReader io.Reader, persistAuthConfig restclient.AuthProviderConfigPersister) (*restclient.Config, error) {
mergedConfig := &restclient.Config{}
// blindly overwrite existing values based on precedence
if len(configAuthInfo.Token) > 0 {
@ -217,7 +217,7 @@ func (config *DirectClientConfig) getUserIdentificationPartialConfig(configAuthI
mergedConfig.BearerToken = string(tokenBytes)
}
if len(configAuthInfo.Impersonate) > 0 {
mergedConfig.Impersonate = rest.ImpersonationConfig{UserName: configAuthInfo.Impersonate}
mergedConfig.Impersonate = restclient.ImpersonationConfig{UserName: configAuthInfo.Impersonate}
}
if len(configAuthInfo.ClientCertificate) > 0 || len(configAuthInfo.ClientCertificateData) > 0 {
mergedConfig.CertFile = configAuthInfo.ClientCertificate
@ -248,7 +248,7 @@ func (config *DirectClientConfig) getUserIdentificationPartialConfig(configAuthI
}
promptedConfig := makeUserIdentificationConfig(*promptedAuthInfo)
previouslyMergedConfig := mergedConfig
mergedConfig = &rest.Config{}
mergedConfig = &restclient.Config{}
mergo.Merge(mergedConfig, promptedConfig)
mergo.Merge(mergedConfig, previouslyMergedConfig)
config.promptedCredentials.username = mergedConfig.Username
@ -259,8 +259,8 @@ func (config *DirectClientConfig) getUserIdentificationPartialConfig(configAuthI
}
// makeUserIdentificationFieldsConfig returns a client.Config capable of being merged using mergo for only user identification information
func makeUserIdentificationConfig(info clientauth.Info) *rest.Config {
config := &rest.Config{}
func makeUserIdentificationConfig(info clientauth.Info) *restclient.Config {
config := &restclient.Config{}
config.Username = info.User
config.Password = info.Password
config.CertFile = info.CertFile
@ -270,8 +270,8 @@ func makeUserIdentificationConfig(info clientauth.Info) *rest.Config {
}
// makeUserIdentificationFieldsConfig returns a client.Config capable of being merged using mergo for only server identification information
func makeServerIdentificationConfig(info clientauth.Info) rest.Config {
config := rest.Config{}
func makeServerIdentificationConfig(info clientauth.Info) restclient.Config {
config := restclient.Config{}
config.CAFile = info.CAFile
if info.Insecure != nil {
config.Insecure = *info.Insecure
@ -279,7 +279,7 @@ func makeServerIdentificationConfig(info clientauth.Info) rest.Config {
return config
}
func canIdentifyUser(config rest.Config) bool {
func canIdentifyUser(config restclient.Config) bool {
return len(config.Username) > 0 ||
(len(config.CertFile) > 0 || len(config.CertData) > 0) ||
len(config.BearerToken) > 0 ||
@ -442,7 +442,7 @@ func (config *DirectClientConfig) getCluster() (clientcmdapi.Cluster, error) {
// Can take options overrides for flags explicitly provided to the command inside the cluster container.
type inClusterClientConfig struct {
overrides *ConfigOverrides
inClusterConfigProvider func() (*rest.Config, error)
inClusterConfigProvider func() (*restclient.Config, error)
}
var _ ClientConfig = &inClusterClientConfig{}
@ -451,9 +451,9 @@ func (config *inClusterClientConfig) RawConfig() (clientcmdapi.Config, error) {
return clientcmdapi.Config{}, fmt.Errorf("inCluster environment config doesn't support multiple clusters")
}
func (config *inClusterClientConfig) ClientConfig() (*rest.Config, error) {
func (config *inClusterClientConfig) ClientConfig() (*restclient.Config, error) {
if config.inClusterConfigProvider == nil {
config.inClusterConfigProvider = rest.InClusterConfig
config.inClusterConfigProvider = restclient.InClusterConfig
}
icc, err := config.inClusterConfigProvider()
@ -512,10 +512,10 @@ func (config *inClusterClientConfig) Possible() bool {
// components. Warnings should reflect this usage. If neither masterUrl or kubeconfigPath
// are passed in we fallback to inClusterConfig. If inClusterConfig fails, we fallback
// to the default config.
func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*rest.Config, error) {
func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*restclient.Config, error) {
if kubeconfigPath == "" && masterUrl == "" {
glog.Warningf("Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.")
kubeconfig, err := rest.InClusterConfig()
kubeconfig, err := restclient.InClusterConfig()
if err == nil {
return kubeconfig, nil
}
@ -528,7 +528,7 @@ func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*rest.Config, error
// BuildConfigFromKubeconfigGetter is a helper function that builds configs from a master
// url and a kubeconfigGetter.
func BuildConfigFromKubeconfigGetter(masterUrl string, kubeconfigGetter KubeconfigGetter) (*rest.Config, error) {
func BuildConfigFromKubeconfigGetter(masterUrl string, kubeconfigGetter KubeconfigGetter) (*restclient.Config, error) {
// TODO: We do not need a DeferredLoader here. Refactor code and see if we can use DirectClientConfig here.
cc := NewNonInteractiveDeferredLoadingClientConfig(
&ClientConfigGetter{kubeconfigGetter: kubeconfigGetter},

View File

@ -24,7 +24,7 @@ import (
"testing"
"github.com/imdario/mergo"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)
@ -448,11 +448,11 @@ func TestInClusterClientConfigPrecedence(t *testing.T) {
expectedCAFile := "/path/to/ca-from-cluster.crt"
icc := &inClusterClientConfig{
inClusterConfigProvider: func() (*rest.Config, error) {
return &rest.Config{
inClusterConfigProvider: func() (*restclient.Config, error) {
return &restclient.Config{
Host: expectedServer,
BearerToken: expectedToken,
TLSClientConfig: rest.TLSClientConfig{
TLSClientConfig: restclient.TLSClientConfig{
CAFile: expectedCAFile,
},
}, nil

View File

@ -26,7 +26,7 @@ import (
"github.com/golang/glog"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)
@ -325,7 +325,7 @@ func ModifyConfig(configAccess ConfigAccess, newConfig clientcmdapi.Config, rela
return nil
}
func PersisterForUser(configAccess ConfigAccess, user string) rest.AuthProviderConfigPersister {
func PersisterForUser(configAccess ConfigAccess, user string) restclient.AuthProviderConfigPersister {
return &persister{configAccess, user}
}

View File

@ -34,7 +34,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/client-go/pkg/util/homedir"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
clientcmdlatest "k8s.io/client-go/tools/clientcmd/api/latest"
)
@ -68,7 +68,7 @@ func currentMigrationRules() map[string]string {
type ClientConfigLoader interface {
ConfigAccess
// IsDefaultConfig returns true if the returned config matches the defaults.
IsDefaultConfig(*rest.Config) bool
IsDefaultConfig(*restclient.Config) bool
// Load returns the latest config
Load() (*clientcmdapi.Config, error)
}
@ -101,7 +101,7 @@ func (g *ClientConfigGetter) IsExplicitFile() bool {
func (g *ClientConfigGetter) GetExplicitFile() string {
return ""
}
func (g *ClientConfigGetter) IsDefaultConfig(config *rest.Config) bool {
func (g *ClientConfigGetter) IsDefaultConfig(config *restclient.Config) bool {
return false
}
@ -330,7 +330,7 @@ func (rules *ClientConfigLoadingRules) GetExplicitFile() string {
}
// IsDefaultConfig returns true if the provided configuration matches the default
func (rules *ClientConfigLoadingRules) IsDefaultConfig(config *rest.Config) bool {
func (rules *ClientConfigLoadingRules) IsDefaultConfig(config *restclient.Config) bool {
if rules.DefaultClientConfig == nil {
return false
}

View File

@ -22,7 +22,7 @@ import (
"github.com/golang/glog"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)
@ -94,7 +94,7 @@ func (config *DeferredLoadingClientConfig) RawConfig() (clientcmdapi.Config, err
}
// ClientConfig implements ClientConfig
func (config *DeferredLoadingClientConfig) ClientConfig() (*rest.Config, error) {
func (config *DeferredLoadingClientConfig) ClientConfig() (*restclient.Config, error) {
mergedClientConfig, err := config.createClientConfig()
if err != nil {
return nil, err

View File

@ -20,7 +20,7 @@ import (
"fmt"
"testing"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)
@ -38,7 +38,7 @@ func (l *testLoader) Load() (*clientcmdapi.Config, error) {
}
type testClientConfig struct {
config *rest.Config
config *restclient.Config
namespace string
namespaceSpecified bool
err error
@ -47,7 +47,7 @@ type testClientConfig struct {
func (c *testClientConfig) RawConfig() (clientcmdapi.Config, error) {
return clientcmdapi.Config{}, fmt.Errorf("unexpected call")
}
func (c *testClientConfig) ClientConfig() (*rest.Config, error) {
func (c *testClientConfig) ClientConfig() (*restclient.Config, error) {
return c.config, c.err
}
func (c *testClientConfig) Namespace() (string, bool, error) {
@ -95,7 +95,7 @@ func TestInClusterConfig(t *testing.T) {
if err != nil {
t.Fatal(err)
}
config2 := &rest.Config{Host: "config2"}
config2 := &restclient.Config{Host: "config2"}
err1 := fmt.Errorf("unique error")
testCases := map[string]struct {
@ -104,7 +104,7 @@ func TestInClusterConfig(t *testing.T) {
defaultConfig *DirectClientConfig
checkedICC bool
result *rest.Config
result *restclient.Config
err error
}{
"in-cluster checked on other error": {

View File

@ -28,7 +28,7 @@ import (
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/util/clock"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
"net/http"
@ -188,7 +188,7 @@ func recordEvent(sink EventSink, event *v1.Event, patch []byte, updateExistingEv
// If we can't contact the server, then hold everything while we keep trying.
// Otherwise, something about the event is malformed and we should abandon it.
switch err.(type) {
case *rest.RequestConstructionError:
case *restclient.RequestConstructionError:
// We will construct the request the same next time, so don't keep trying.
glog.Errorf("Unable to construct event '%#v': '%v' (will not retry!)", event, err)
return true

View File

@ -32,7 +32,7 @@ import (
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/util/clock"
"k8s.io/client-go/pkg/util/strategicpatch"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
)
type testEventSink struct {
@ -387,7 +387,7 @@ func TestWriteEventError(t *testing.T) {
"giveUp1": {
timesToSendError: 1000,
attemptsWanted: 1,
err: &rest.RequestConstructionError{},
err: &restclient.RequestConstructionError{},
},
"giveUp2": {
timesToSendError: 1000,

View File

@ -244,7 +244,7 @@ func (e *eventLogger) eventObserve(newEvent *v1.Event) (*v1.Event, []byte, error
newData, _ := json.Marshal(event)
oldData, _ := json.Marshal(eventCopy2)
patch, err = strategicpatch.CreateStrategicMergePatch(oldData, newData, event)
patch, err = strategicpatch.CreateTwoWayMergePatch(oldData, newData, event)
}
// record our new observation

View File

@ -14,6 +14,5 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
type PodDisruptionBudgetExpansion interface{}
// package openapi holds shared codes and types between open API code generator and spec generator.
package openapi