Update godeps

This commit is contained in:
Manuel Alejandro de Brito Fontes 2016-03-19 20:00:11 -03:00 committed by Manuel de Brito Fontes
parent ffe6baa14c
commit 9b142b56f8
1137 changed files with 22773 additions and 189176 deletions

View file

@ -0,0 +1,6 @@
assignees:
- bgrant0607
- erictune
- lavalamp
- smarterclayton
- thockin

View file

@ -1,68 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api_test
import (
"testing"
"k8s.io/kubernetes/pkg/api"
)
// TestNamespaceContext validates that a namespace can be get/set on a context object
func TestNamespaceContext(t *testing.T) {
ctx := api.NewDefaultContext()
result, ok := api.NamespaceFrom(ctx)
if !ok {
t.Errorf("Error getting namespace")
}
if api.NamespaceDefault != result {
t.Errorf("Expected: %v, Actual: %v", api.NamespaceDefault, result)
}
ctx = api.NewContext()
result, ok = api.NamespaceFrom(ctx)
if ok {
t.Errorf("Should not be ok because there is no namespace on the context")
}
}
// TestValidNamespace validates that namespace rules are enforced on a resource prior to create or update
func TestValidNamespace(t *testing.T) {
ctx := api.NewDefaultContext()
namespace, _ := api.NamespaceFrom(ctx)
resource := api.ReplicationController{}
if !api.ValidNamespace(ctx, &resource.ObjectMeta) {
t.Errorf("expected success")
}
if namespace != resource.Namespace {
t.Errorf("expected resource to have the default namespace assigned during validation")
}
resource = api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: "other"}}
if api.ValidNamespace(ctx, &resource.ObjectMeta) {
t.Errorf("Expected error that resource and context errors do not match because resource has different namespace")
}
ctx = api.NewContext()
if api.ValidNamespace(ctx, &resource.ObjectMeta) {
t.Errorf("Expected error that resource and context errors do not match since context has no namespace")
}
ctx = api.NewContext()
ns := api.NamespaceValue(ctx)
if ns != "" {
t.Errorf("Expected the empty string")
}
}

View file

@ -41,6 +41,7 @@ func init() {
Convert_unversioned_ListMeta_To_unversioned_ListMeta,
Convert_intstr_IntOrString_To_intstr_IntOrString,
Convert_unversioned_Time_To_unversioned_Time,
Convert_string_slice_To_unversioned_Time,
Convert_string_To_labels_Selector,
Convert_string_To_fields_Selector,
Convert_bool_ref_To_bool,
@ -116,6 +117,16 @@ func Convert_unversioned_Time_To_unversioned_Time(in *unversioned.Time, out *unv
*out = *in
return nil
}
// Convert_string_slice_To_unversioned_Time allows converting a URL query parameter value
func Convert_string_slice_To_unversioned_Time(input *[]string, out *unversioned.Time, s conversion.Scope) error {
str := ""
if len(*input) > 0 {
str = (*input)[0]
}
return out.UnmarshalQueryParameter(str)
}
func Convert_string_To_labels_Selector(in *string, out *labels.Selector, s conversion.Scope) error {
selector, err := labels.Parse(*in)
if err != nil {

View file

@ -1,110 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api_test
import (
"io/ioutil"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/runtime"
)
func BenchmarkPodConversion(b *testing.B) {
data, err := ioutil.ReadFile("pod_example.json")
if err != nil {
b.Fatalf("Unexpected error while reading file: %v", err)
}
var pod api.Pod
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &pod); err != nil {
b.Fatalf("Unexpected error decoding pod: %v", err)
}
scheme := api.Scheme
var result *api.Pod
for i := 0; i < b.N; i++ {
versionedObj, err := scheme.ConvertToVersion(&pod, testapi.Default.GroupVersion().String())
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
obj, err := scheme.ConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion().String())
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
result = obj.(*api.Pod)
}
if !api.Semantic.DeepDerivative(pod, *result) {
b.Fatalf("Incorrect conversion: expected %v, got %v", pod, *result)
}
}
func BenchmarkNodeConversion(b *testing.B) {
data, err := ioutil.ReadFile("node_example.json")
if err != nil {
b.Fatalf("Unexpected error while reading file: %v", err)
}
var node api.Node
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &node); err != nil {
b.Fatalf("Unexpected error decoding node: %v", err)
}
scheme := api.Scheme
var result *api.Node
for i := 0; i < b.N; i++ {
versionedObj, err := scheme.ConvertToVersion(&node, testapi.Default.GroupVersion().String())
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
obj, err := scheme.ConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion().String())
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
result = obj.(*api.Node)
}
if !api.Semantic.DeepDerivative(node, *result) {
b.Fatalf("Incorrect conversion: expected %v, got %v", node, *result)
}
}
func BenchmarkReplicationControllerConversion(b *testing.B) {
data, err := ioutil.ReadFile("replication_controller_example.json")
if err != nil {
b.Fatalf("Unexpected error while reading file: %v", err)
}
var replicationController api.ReplicationController
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &replicationController); err != nil {
b.Fatalf("Unexpected error decoding node: %v", err)
}
scheme := api.Scheme
var result *api.ReplicationController
for i := 0; i < b.N; i++ {
versionedObj, err := scheme.ConvertToVersion(&replicationController, testapi.Default.GroupVersion().String())
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
obj, err := scheme.ConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion().String())
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
result = obj.(*api.ReplicationController)
}
if !api.Semantic.DeepDerivative(replicationController, *result) {
b.Fatalf("Incorrect conversion: expected %v, got %v", replicationController, *result)
}
}

View file

@ -1,68 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api_test
import (
"math/rand"
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/util"
"github.com/google/gofuzz"
)
func TestDeepCopyApiObjects(t *testing.T) {
for i := 0; i < *fuzzIters; i++ {
for _, version := range []unversioned.GroupVersion{testapi.Default.InternalGroupVersion(), *testapi.Default.GroupVersion()} {
f := apitesting.FuzzerFor(t, version, rand.NewSource(rand.Int63()))
for kind := range api.Scheme.KnownTypes(version) {
doDeepCopyTest(t, version.WithKind(kind), f)
}
}
}
}
func doDeepCopyTest(t *testing.T, kind unversioned.GroupVersionKind, f *fuzz.Fuzzer) {
item, err := api.Scheme.New(kind)
if err != nil {
t.Fatalf("Could not create a %v: %s", kind, err)
}
f.Fuzz(item)
itemCopy, err := api.Scheme.DeepCopy(item)
if err != nil {
t.Errorf("Could not deep copy a %v: %s", kind, err)
return
}
if !reflect.DeepEqual(item, itemCopy) {
t.Errorf("\nexpected: %#v\n\ngot: %#v\n\ndiff: %v", item, itemCopy, util.ObjectGoPrintSideBySide(item, itemCopy))
}
}
func TestDeepCopySingleType(t *testing.T) {
for i := 0; i < *fuzzIters; i++ {
for _, version := range []unversioned.GroupVersion{testapi.Default.InternalGroupVersion(), *testapi.Default.GroupVersion()} {
f := apitesting.FuzzerFor(t, version, rand.NewSource(rand.Int63()))
doDeepCopyTest(t, version.WithKind("Pod"), f)
}
}
}

View file

@ -2400,6 +2400,7 @@ func DeepCopy_api_ReplicationControllerSpec(in ReplicationControllerSpec, out *R
func DeepCopy_api_ReplicationControllerStatus(in ReplicationControllerStatus, out *ReplicationControllerStatus, c *conversion.Cloner) error {
out.Replicas = in.Replicas
out.FullyLabeledReplicas = in.FullyLabeledReplicas
out.ObservedGeneration = in.ObservedGeneration
return nil
}
@ -2455,6 +2456,15 @@ func DeepCopy_api_ResourceQuotaSpec(in ResourceQuotaSpec, out *ResourceQuotaSpec
} else {
out.Hard = nil
}
if in.Scopes != nil {
in, out := in.Scopes, &out.Scopes
*out = make([]ResourceQuotaScope, len(in))
for i := range in {
(*out)[i] = in[i]
}
} else {
out.Scopes = nil
}
return nil
}

View file

@ -1,95 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api_test
import (
"io/ioutil"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/runtime"
)
func BenchmarkPodCopy(b *testing.B) {
data, err := ioutil.ReadFile("pod_example.json")
if err != nil {
b.Fatalf("Unexpected error while reading file: %v", err)
}
var pod api.Pod
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &pod); err != nil {
b.Fatalf("Unexpected error decoding pod: %v", err)
}
var result *api.Pod
for i := 0; i < b.N; i++ {
obj, err := api.Scheme.DeepCopy(&pod)
if err != nil {
b.Fatalf("Unexpected error copying pod: %v", err)
}
result = obj.(*api.Pod)
}
if !api.Semantic.DeepEqual(pod, *result) {
b.Fatalf("Incorrect copy: expected %v, got %v", pod, *result)
}
}
func BenchmarkNodeCopy(b *testing.B) {
data, err := ioutil.ReadFile("node_example.json")
if err != nil {
b.Fatalf("Unexpected error while reading file: %v", err)
}
var node api.Node
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &node); err != nil {
b.Fatalf("Unexpected error decoding node: %v", err)
}
var result *api.Node
for i := 0; i < b.N; i++ {
obj, err := api.Scheme.DeepCopy(&node)
if err != nil {
b.Fatalf("Unexpected error copying node: %v", err)
}
result = obj.(*api.Node)
}
if !api.Semantic.DeepEqual(node, *result) {
b.Fatalf("Incorrect copy: expected %v, got %v", node, *result)
}
}
func BenchmarkReplicationControllerCopy(b *testing.B) {
data, err := ioutil.ReadFile("replication_controller_example.json")
if err != nil {
b.Fatalf("Unexpected error while reading file: %v", err)
}
var replicationController api.ReplicationController
if err := runtime.DecodeInto(testapi.Default.Codec(), data, &replicationController); err != nil {
b.Fatalf("Unexpected error decoding node: %v", err)
}
var result *api.ReplicationController
for i := 0; i < b.N; i++ {
obj, err := api.Scheme.DeepCopy(&replicationController)
if err != nil {
b.Fatalf("Unexpected error copying replication controller: %v", err)
}
result = obj.(*api.ReplicationController)
}
if !api.Semantic.DeepEqual(replicationController, *result) {
b.Fatalf("Incorrect copy: expected %v, got %v", replicationController, *result)
}
}

View file

@ -28,6 +28,16 @@ import (
hashutil "k8s.io/kubernetes/pkg/util/hash"
)
const (
// Its value is the json representation of map[string(IP)][HostRecord]
// example: '{"10.245.1.6":{"HostName":"my-webserver"}}'
PodHostnamesAnnotation = "endpoints.beta.kubernetes.io/hostnames-map"
)
type HostRecord struct {
HostName string
}
// RepackSubsets takes a slice of EndpointSubset objects, expands it to the full
// representation, and then repacks that into the canonical layout. This
// ensures that code which operates on these objects can rely on the common

View file

@ -1,444 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package endpoints
import (
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/types"
)
func podRef(uid string) *api.ObjectReference {
ref := api.ObjectReference{UID: types.UID(uid)}
return &ref
}
func TestPackSubsets(t *testing.T) {
// The downside of table-driven tests is that some things have to live outside the table.
fooObjRef := api.ObjectReference{Name: "foo"}
barObjRef := api.ObjectReference{Name: "bar"}
testCases := []struct {
name string
given []api.EndpointSubset
expect []api.EndpointSubset
}{
{
name: "empty everything",
given: []api.EndpointSubset{{Addresses: []api.EndpointAddress{}, Ports: []api.EndpointPort{}}},
expect: []api.EndpointSubset{},
}, {
name: "empty addresses",
given: []api.EndpointSubset{{Addresses: []api.EndpointAddress{}, Ports: []api.EndpointPort{{Port: 111}}}},
expect: []api.EndpointSubset{},
}, {
name: "empty ports",
given: []api.EndpointSubset{{Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}}, Ports: []api.EndpointPort{}}},
expect: []api.EndpointSubset{},
}, {
name: "empty ports",
given: []api.EndpointSubset{{NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}}, Ports: []api.EndpointPort{}}},
expect: []api.EndpointSubset{},
}, {
name: "one set, one ip, one port",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "one set, one notReady ip, one port",
given: []api.EndpointSubset{{
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "one set, one ip, one UID, one port",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "one set, one notReady ip, one UID, one port",
given: []api.EndpointSubset{{
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "one set, one ip, empty UID, one port",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("")}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("")}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "one set, one notReady ip, empty UID, one port",
given: []api.EndpointSubset{{
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("")}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("")}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "one set, two ips, one port",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "one set, two mixed ips, one port",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
NotReadyAddresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
NotReadyAddresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "one set, two duplicate ips, one port, notReady is covered by ready",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "one set, one ip, two ports",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}, {Port: 222}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}, {Port: 222}},
}},
}, {
name: "one set, dup ips, one port",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "one set, dup ips with target-refs, one port",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{
{IP: "1.2.3.4", TargetRef: &fooObjRef},
{IP: "1.2.3.4", TargetRef: &barObjRef},
},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: &fooObjRef}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "one set, dup mixed ips with target-refs, one port",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{
{IP: "1.2.3.4", TargetRef: &fooObjRef},
},
NotReadyAddresses: []api.EndpointAddress{
{IP: "1.2.3.4", TargetRef: &barObjRef},
},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
// finding the same address twice is considered an error on input, only the first address+port
// reference is preserved
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: &fooObjRef}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "one set, one ip, dup ports",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}, {Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "two sets, dup ip, dup port",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "two sets, dup mixed ip, dup port",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "two sets, dup ip, two ports",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 222}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}, {Port: 222}},
}},
}, {
name: "two sets, dup ip, dup uids, two ports",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 222}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 111}, {Port: 222}},
}},
}, {
name: "two sets, dup mixed ip, dup uids, two ports",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 222}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 222}},
}},
}, {
name: "two sets, two ips, dup port",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "two set, dup ip, two uids, dup ports",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-2")}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{
{IP: "1.2.3.4", TargetRef: podRef("uid-1")},
{IP: "1.2.3.4", TargetRef: podRef("uid-2")},
},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "two set, dup ip, with and without uid, dup ports",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-2")}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{
{IP: "1.2.3.4"},
{IP: "1.2.3.4", TargetRef: podRef("uid-2")},
},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "two sets, two ips, two dup ip with uid, dup port, wrong order",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "5.6.7.8", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{
{IP: "1.2.3.4"},
{IP: "1.2.3.4", TargetRef: podRef("uid-1")},
{IP: "5.6.7.8"},
{IP: "5.6.7.8", TargetRef: podRef("uid-1")},
},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "two sets, two mixed ips, two dup ip with uid, dup port, wrong order, ends up with split addresses",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
NotReadyAddresses: []api.EndpointAddress{{IP: "5.6.7.8", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: podRef("uid-1")}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{
{IP: "5.6.7.8"},
},
NotReadyAddresses: []api.EndpointAddress{
{IP: "1.2.3.4"},
{IP: "1.2.3.4", TargetRef: podRef("uid-1")},
{IP: "5.6.7.8", TargetRef: podRef("uid-1")},
},
Ports: []api.EndpointPort{{Port: 111}},
}},
}, {
name: "two sets, two ips, two ports",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
Ports: []api.EndpointPort{{Port: 222}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "5.6.7.8"}},
Ports: []api.EndpointPort{{Port: 222}},
}},
}, {
name: "four sets, three ips, three ports, jumbled",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "1.2.3.5"}},
Ports: []api.EndpointPort{{Port: 222}},
}, {
Addresses: []api.EndpointAddress{{IP: "1.2.3.6"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "1.2.3.5"}},
Ports: []api.EndpointPort{{Port: 333}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "1.2.3.6"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
Addresses: []api.EndpointAddress{{IP: "1.2.3.5"}},
Ports: []api.EndpointPort{{Port: 222}, {Port: 333}},
}},
}, {
name: "four sets, three mixed ips, three ports, jumbled",
given: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.5"}},
Ports: []api.EndpointPort{{Port: 222}},
}, {
Addresses: []api.EndpointAddress{{IP: "1.2.3.6"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.5"}},
Ports: []api.EndpointPort{{Port: 333}},
}},
expect: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "1.2.3.6"}},
Ports: []api.EndpointPort{{Port: 111}},
}, {
NotReadyAddresses: []api.EndpointAddress{{IP: "1.2.3.5"}},
Ports: []api.EndpointPort{{Port: 222}, {Port: 333}},
}},
},
}
for _, tc := range testCases {
result := RepackSubsets(tc.given)
if !reflect.DeepEqual(result, SortSubsets(tc.expect)) {
t.Errorf("case %q: expected %s, got %s", tc.name, spew.Sprintf("%#v", SortSubsets(tc.expect)), spew.Sprintf("%#v", result))
}
}
}

View file

@ -1,189 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package errors
import (
"errors"
"fmt"
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/validation/field"
)
func TestErrorNew(t *testing.T) {
err := NewAlreadyExists(api.Resource("tests"), "1")
if !IsAlreadyExists(err) {
t.Errorf("expected to be %s", unversioned.StatusReasonAlreadyExists)
}
if IsConflict(err) {
t.Errorf("expected to not be %s", unversioned.StatusReasonConflict)
}
if IsNotFound(err) {
t.Errorf(fmt.Sprintf("expected to not be %s", unversioned.StatusReasonNotFound))
}
if IsInvalid(err) {
t.Errorf("expected to not be %s", unversioned.StatusReasonInvalid)
}
if IsBadRequest(err) {
t.Errorf("expected to not be %s", unversioned.StatusReasonBadRequest)
}
if IsForbidden(err) {
t.Errorf("expected to not be %s", unversioned.StatusReasonForbidden)
}
if IsServerTimeout(err) {
t.Errorf("expected to not be %s", unversioned.StatusReasonServerTimeout)
}
if IsMethodNotSupported(err) {
t.Errorf("expected to not be %s", unversioned.StatusReasonMethodNotAllowed)
}
if !IsConflict(NewConflict(api.Resource("tests"), "2", errors.New("message"))) {
t.Errorf("expected to be conflict")
}
if !IsNotFound(NewNotFound(api.Resource("tests"), "3")) {
t.Errorf("expected to be %s", unversioned.StatusReasonNotFound)
}
if !IsInvalid(NewInvalid(api.Kind("Test"), "2", nil)) {
t.Errorf("expected to be %s", unversioned.StatusReasonInvalid)
}
if !IsBadRequest(NewBadRequest("reason")) {
t.Errorf("expected to be %s", unversioned.StatusReasonBadRequest)
}
if !IsForbidden(NewForbidden(api.Resource("tests"), "2", errors.New("reason"))) {
t.Errorf("expected to be %s", unversioned.StatusReasonForbidden)
}
if !IsUnauthorized(NewUnauthorized("reason")) {
t.Errorf("expected to be %s", unversioned.StatusReasonUnauthorized)
}
if !IsServerTimeout(NewServerTimeout(api.Resource("tests"), "reason", 0)) {
t.Errorf("expected to be %s", unversioned.StatusReasonServerTimeout)
}
if time, ok := SuggestsClientDelay(NewServerTimeout(api.Resource("tests"), "doing something", 10)); time != 10 || !ok {
t.Errorf("expected to be %s", unversioned.StatusReasonServerTimeout)
}
if time, ok := SuggestsClientDelay(NewTimeoutError("test reason", 10)); time != 10 || !ok {
t.Errorf("expected to be %s", unversioned.StatusReasonTimeout)
}
if !IsMethodNotSupported(NewMethodNotSupported(api.Resource("foos"), "delete")) {
t.Errorf("expected to be %s", unversioned.StatusReasonMethodNotAllowed)
}
}
func TestNewInvalid(t *testing.T) {
testCases := []struct {
Err *field.Error
Details *unversioned.StatusDetails
}{
{
field.Duplicate(field.NewPath("field[0].name"), "bar"),
&unversioned.StatusDetails{
Kind: "Kind",
Name: "name",
Causes: []unversioned.StatusCause{{
Type: unversioned.CauseTypeFieldValueDuplicate,
Field: "field[0].name",
}},
},
},
{
field.Invalid(field.NewPath("field[0].name"), "bar", "detail"),
&unversioned.StatusDetails{
Kind: "Kind",
Name: "name",
Causes: []unversioned.StatusCause{{
Type: unversioned.CauseTypeFieldValueInvalid,
Field: "field[0].name",
}},
},
},
{
field.NotFound(field.NewPath("field[0].name"), "bar"),
&unversioned.StatusDetails{
Kind: "Kind",
Name: "name",
Causes: []unversioned.StatusCause{{
Type: unversioned.CauseTypeFieldValueNotFound,
Field: "field[0].name",
}},
},
},
{
field.NotSupported(field.NewPath("field[0].name"), "bar", nil),
&unversioned.StatusDetails{
Kind: "Kind",
Name: "name",
Causes: []unversioned.StatusCause{{
Type: unversioned.CauseTypeFieldValueNotSupported,
Field: "field[0].name",
}},
},
},
{
field.Required(field.NewPath("field[0].name"), ""),
&unversioned.StatusDetails{
Kind: "Kind",
Name: "name",
Causes: []unversioned.StatusCause{{
Type: unversioned.CauseTypeFieldValueRequired,
Field: "field[0].name",
}},
},
},
}
for i, testCase := range testCases {
vErr, expected := testCase.Err, testCase.Details
expected.Causes[0].Message = vErr.ErrorBody()
err := NewInvalid(api.Kind("Kind"), "name", field.ErrorList{vErr})
status := err.(*StatusError).ErrStatus
if status.Code != 422 || status.Reason != unversioned.StatusReasonInvalid {
t.Errorf("%d: unexpected status: %#v", i, status)
}
if !reflect.DeepEqual(expected, status.Details) {
t.Errorf("%d: expected %#v, got %#v", i, expected, status.Details)
}
}
}
func Test_reasonForError(t *testing.T) {
if e, a := unversioned.StatusReasonUnknown, reasonForError(nil); e != a {
t.Errorf("unexpected reason type: %#v", a)
}
}
type TestType struct{}
func (obj *TestType) GetObjectKind() unversioned.ObjectKind { return unversioned.EmptyObjectKind }
func TestFromObject(t *testing.T) {
table := []struct {
obj runtime.Object
message string
}{
{&unversioned.Status{Message: "foobar"}, "foobar"},
{&TestType{}, "unexpected object: &{}"},
}
for _, item := range table {
if e, a := item.message, FromObject(item.obj).Error(); e != a {
t.Errorf("Expected %v, got %v", e, a)
}
}
}

View file

@ -1,18 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package etcd provides conversion of etcd errors to API errors.
package etcd

View file

@ -1,88 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package etcd
import (
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/storage"
)
// InterpretListError converts a generic error on a retrieval
// operation into the appropriate API error.
func InterpretListError(err error, qualifiedResource unversioned.GroupResource) error {
switch {
case storage.IsNotFound(err):
return errors.NewNotFound(qualifiedResource, "")
case storage.IsUnreachable(err):
return errors.NewServerTimeout(qualifiedResource, "list", 2) // TODO: make configurable or handled at a higher level
default:
return err
}
}
// InterpretGetError converts a generic error on a retrieval
// operation into the appropriate API error.
func InterpretGetError(err error, qualifiedResource unversioned.GroupResource, name string) error {
switch {
case storage.IsNotFound(err):
return errors.NewNotFound(qualifiedResource, name)
case storage.IsUnreachable(err):
return errors.NewServerTimeout(qualifiedResource, "get", 2) // TODO: make configurable or handled at a higher level
default:
return err
}
}
// InterpretCreateError converts a generic error on a create
// operation into the appropriate API error.
func InterpretCreateError(err error, qualifiedResource unversioned.GroupResource, name string) error {
switch {
case storage.IsNodeExist(err):
return errors.NewAlreadyExists(qualifiedResource, name)
case storage.IsUnreachable(err):
return errors.NewServerTimeout(qualifiedResource, "create", 2) // TODO: make configurable or handled at a higher level
default:
return err
}
}
// InterpretUpdateError converts a generic error on a update
// operation into the appropriate API error.
func InterpretUpdateError(err error, qualifiedResource unversioned.GroupResource, name string) error {
switch {
case storage.IsTestFailed(err), storage.IsNodeExist(err):
return errors.NewConflict(qualifiedResource, name, err)
case storage.IsUnreachable(err):
return errors.NewServerTimeout(qualifiedResource, "update", 2) // TODO: make configurable or handled at a higher level
default:
return err
}
}
// InterpretDeleteError converts a generic error on a delete
// operation into the appropriate API error.
func InterpretDeleteError(err error, qualifiedResource unversioned.GroupResource, name string) error {
switch {
case storage.IsNotFound(err):
return errors.NewNotFound(qualifiedResource, name)
case storage.IsUnreachable(err):
return errors.NewServerTimeout(qualifiedResource, "delete", 2) // TODO: make configurable or handled at a higher level
default:
return err
}
}

View file

@ -0,0 +1,38 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api
// Field path constants that are specific to the internal API
// representation.
const (
NodeUnschedulableField = "spec.unschedulable"
ObjectNameField = "metadata.name"
PodHostField = "spec.nodeName"
PodStatusField = "status.phase"
SecretTypeField = "type"
EventReasonField = "reason"
EventSourceField = "source"
EventTypeField = "type"
EventInvolvedKindField = "involvedObject.kind"
EventInvolvedNamespaceField = "involvedObject.namespace"
EventInvolvedNameField = "involvedObject.name"
EventInvolvedUIDField = "involvedObject.uid"
EventInvolvedAPIVersionField = "involvedObject.apiVersion"
EventInvolvedResourceVersionField = "involvedObject.resourceVersion"
EventInvolvedFieldPathField = "involvedObject.fieldPath"
)

View file

@ -1,79 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api
import (
"strings"
"testing"
)
type nameGeneratorFunc func(base string) string
func (fn nameGeneratorFunc) GenerateName(base string) string {
return fn(base)
}
func TestGenerateName(t *testing.T) {
testCases := []struct {
meta ObjectMeta
base string
returned string
}{
{
returned: "",
},
{
meta: ObjectMeta{
GenerateName: "test",
},
base: "test",
returned: "test",
},
{
meta: ObjectMeta{
Name: "foo",
GenerateName: "test",
},
base: "test",
returned: "foo",
},
}
for i, testCase := range testCases {
GenerateName(nameGeneratorFunc(func(base string) string {
if base != testCase.base {
t.Errorf("%d: unexpected call with base", i)
}
return "test"
}), &testCase.meta)
expect := testCase.returned
if expect != testCase.meta.Name {
t.Errorf("%d: unexpected name: %#v", i, testCase.meta)
}
}
}
func TestSimpleNameGenerator(t *testing.T) {
meta := &ObjectMeta{
GenerateName: "foo",
}
GenerateName(SimpleNameGenerator, meta)
if !strings.HasPrefix(meta.Name, "foo") || meta.Name == "foo" {
t.Errorf("unexpected name: %#v", meta)
}
}

View file

@ -79,15 +79,100 @@ var Semantic = conversion.EqualitiesOrDie(
},
)
var standardResources = sets.NewString(
var standardResourceQuotaScopes = sets.NewString(
string(ResourceQuotaScopeTerminating),
string(ResourceQuotaScopeNotTerminating),
string(ResourceQuotaScopeBestEffort),
string(ResourceQuotaScopeNotBestEffort),
)
// IsStandardResourceQuotaScope returns true if the scope is a standard value
func IsStandardResourceQuotaScope(str string) bool {
return standardResourceQuotaScopes.Has(str)
}
var podObjectCountQuotaResources = sets.NewString(
string(ResourcePods),
)
var podComputeQuotaResources = sets.NewString(
string(ResourceCPU),
string(ResourceMemory),
string(ResourceLimitsCPU),
string(ResourceLimitsMemory),
string(ResourceRequestsCPU),
string(ResourceRequestsMemory),
)
// IsResourceQuotaScopeValidForResource returns true if the resource applies to the specified scope
func IsResourceQuotaScopeValidForResource(scope ResourceQuotaScope, resource string) bool {
switch scope {
case ResourceQuotaScopeTerminating, ResourceQuotaScopeNotTerminating, ResourceQuotaScopeNotBestEffort:
return podObjectCountQuotaResources.Has(resource) || podComputeQuotaResources.Has(resource)
case ResourceQuotaScopeBestEffort:
return podObjectCountQuotaResources.Has(resource)
default:
return true
}
}
var standardContainerResources = sets.NewString(
string(ResourceCPU),
string(ResourceMemory),
)
// IsStandardContainerResourceName returns true if the container can make a resource request
// for the specified resource
func IsStandardContainerResourceName(str string) bool {
return standardContainerResources.Has(str)
}
var standardLimitRangeTypes = sets.NewString(
string(LimitTypePod),
string(LimitTypeContainer),
)
// IsStandardLimitRangeType returns true if the type is Pod or Container
func IsStandardLimitRangeType(str string) bool {
return standardLimitRangeTypes.Has(str)
}
var standardQuotaResources = sets.NewString(
string(ResourceCPU),
string(ResourceMemory),
string(ResourceRequestsCPU),
string(ResourceRequestsMemory),
string(ResourceLimitsCPU),
string(ResourceLimitsMemory),
string(ResourcePods),
string(ResourceQuotas),
string(ResourceServices),
string(ResourceReplicationControllers),
string(ResourceSecrets),
string(ResourcePersistentVolumeClaims),
string(ResourceConfigMaps),
)
// IsStandardQuotaResourceName returns true if the resource is known to
// the quota tracking system
func IsStandardQuotaResourceName(str string) bool {
return standardQuotaResources.Has(str)
}
var standardResources = sets.NewString(
string(ResourceCPU),
string(ResourceMemory),
string(ResourceRequestsCPU),
string(ResourceRequestsMemory),
string(ResourceLimitsCPU),
string(ResourceLimitsMemory),
string(ResourcePods),
string(ResourceQuotas),
string(ResourceServices),
string(ResourceReplicationControllers),
string(ResourceSecrets),
string(ResourceConfigMaps),
string(ResourcePersistentVolumeClaims),
string(ResourceStorage),
)
@ -102,6 +187,7 @@ var integerResources = sets.NewString(
string(ResourceServices),
string(ResourceReplicationControllers),
string(ResourceSecrets),
string(ResourceConfigMaps),
string(ResourcePersistentVolumeClaims),
)

View file

@ -1,299 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api
import (
"reflect"
"strings"
"testing"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/labels"
"speter.net/go/exp/math/dec/inf"
)
func TestConversionError(t *testing.T) {
var i int
var s string
i = 3
s = "foo"
c := ConversionError{
In: &i, Out: &s,
Message: "Can't make x into y, silly",
}
var e error
e = &c // ensure it implements error
msg := e.Error()
t.Logf("Message is %v", msg)
for _, part := range []string{"3", "int", "string", "Can't"} {
if !strings.Contains(msg, part) {
t.Errorf("didn't find %v", part)
}
}
}
func TestSemantic(t *testing.T) {
table := []struct {
a, b interface{}
shouldEqual bool
}{
{resource.MustParse("0"), resource.Quantity{}, true},
{resource.Quantity{}, resource.MustParse("0"), true},
{resource.Quantity{}, resource.MustParse("1m"), false},
{
resource.Quantity{Amount: inf.NewDec(5, 0), Format: resource.BinarySI},
resource.Quantity{Amount: inf.NewDec(5, 0), Format: resource.DecimalSI},
true,
},
{resource.MustParse("2m"), resource.MustParse("1m"), false},
}
for index, item := range table {
if e, a := item.shouldEqual, Semantic.DeepEqual(item.a, item.b); e != a {
t.Errorf("case[%d], expected %v, got %v.", index, e, a)
}
}
}
func TestIsStandardResource(t *testing.T) {
testCases := []struct {
input string
output bool
}{
{"cpu", true},
{"memory", true},
{"disk", false},
{"blah", false},
{"x.y.z", false},
}
for i, tc := range testCases {
if IsStandardResourceName(tc.input) != tc.output {
t.Errorf("case[%d], expected: %t, got: %t", i, tc.output, !tc.output)
}
}
}
func TestAddToNodeAddresses(t *testing.T) {
testCases := []struct {
existing []NodeAddress
toAdd []NodeAddress
expected []NodeAddress
}{
{
existing: []NodeAddress{},
toAdd: []NodeAddress{},
expected: []NodeAddress{},
},
{
existing: []NodeAddress{},
toAdd: []NodeAddress{
{Type: NodeExternalIP, Address: "1.1.1.1"},
{Type: NodeHostName, Address: "localhost"},
},
expected: []NodeAddress{
{Type: NodeExternalIP, Address: "1.1.1.1"},
{Type: NodeHostName, Address: "localhost"},
},
},
{
existing: []NodeAddress{},
toAdd: []NodeAddress{
{Type: NodeExternalIP, Address: "1.1.1.1"},
{Type: NodeExternalIP, Address: "1.1.1.1"},
},
expected: []NodeAddress{
{Type: NodeExternalIP, Address: "1.1.1.1"},
},
},
{
existing: []NodeAddress{
{Type: NodeExternalIP, Address: "1.1.1.1"},
{Type: NodeInternalIP, Address: "10.1.1.1"},
},
toAdd: []NodeAddress{
{Type: NodeExternalIP, Address: "1.1.1.1"},
{Type: NodeHostName, Address: "localhost"},
},
expected: []NodeAddress{
{Type: NodeExternalIP, Address: "1.1.1.1"},
{Type: NodeInternalIP, Address: "10.1.1.1"},
{Type: NodeHostName, Address: "localhost"},
},
},
}
for i, tc := range testCases {
AddToNodeAddresses(&tc.existing, tc.toAdd...)
if !Semantic.DeepEqual(tc.expected, tc.existing) {
t.Errorf("case[%d], expected: %v, got: %v", i, tc.expected, tc.existing)
}
}
}
func TestGetAccessModesFromString(t *testing.T) {
modes := GetAccessModesFromString("ROX")
if !containsAccessMode(modes, ReadOnlyMany) {
t.Errorf("Expected mode %s, but got %+v", ReadOnlyMany, modes)
}
modes = GetAccessModesFromString("ROX,RWX")
if !containsAccessMode(modes, ReadOnlyMany) {
t.Errorf("Expected mode %s, but got %+v", ReadOnlyMany, modes)
}
if !containsAccessMode(modes, ReadWriteMany) {
t.Errorf("Expected mode %s, but got %+v", ReadWriteMany, modes)
}
modes = GetAccessModesFromString("RWO,ROX,RWX")
if !containsAccessMode(modes, ReadOnlyMany) {
t.Errorf("Expected mode %s, but got %+v", ReadOnlyMany, modes)
}
if !containsAccessMode(modes, ReadWriteMany) {
t.Errorf("Expected mode %s, but got %+v", ReadWriteMany, modes)
}
}
func TestRemoveDuplicateAccessModes(t *testing.T) {
modes := []PersistentVolumeAccessMode{
ReadWriteOnce, ReadOnlyMany, ReadOnlyMany, ReadOnlyMany,
}
modes = removeDuplicateAccessModes(modes)
if len(modes) != 2 {
t.Errorf("Expected 2 distinct modes in set but found %v", len(modes))
}
}
func TestNodeSelectorRequirementsAsSelector(t *testing.T) {
matchExpressions := []NodeSelectorRequirement{{
Key: "foo",
Operator: NodeSelectorOpIn,
Values: []string{"bar", "baz"},
}}
mustParse := func(s string) labels.Selector {
out, e := labels.Parse(s)
if e != nil {
panic(e)
}
return out
}
tc := []struct {
in []NodeSelectorRequirement
out labels.Selector
expectErr bool
}{
{in: nil, out: labels.Nothing()},
{in: []NodeSelectorRequirement{}, out: labels.Nothing()},
{
in: matchExpressions,
out: mustParse("foo in (baz,bar)"),
},
{
in: []NodeSelectorRequirement{{
Key: "foo",
Operator: NodeSelectorOpExists,
Values: []string{"bar", "baz"},
}},
expectErr: true,
},
{
in: []NodeSelectorRequirement{{
Key: "foo",
Operator: NodeSelectorOpGt,
Values: []string{"1.1"},
}},
out: mustParse("foo>1.1"),
},
{
in: []NodeSelectorRequirement{{
Key: "bar",
Operator: NodeSelectorOpLt,
Values: []string{"7.1"},
}},
out: mustParse("bar<7.1"),
},
}
for i, tc := range tc {
out, err := NodeSelectorRequirementsAsSelector(tc.in)
if err == nil && tc.expectErr {
t.Errorf("[%v]expected error but got none.", i)
}
if err != nil && !tc.expectErr {
t.Errorf("[%v]did not expect error but got: %v", i, err)
}
if !reflect.DeepEqual(out, tc.out) {
t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out)
}
}
}
func TestGetAffinityFromPod(t *testing.T) {
testCases := []struct {
pod *Pod
expectErr bool
}{
{
pod: &Pod{},
expectErr: false,
},
{
pod: &Pod{
ObjectMeta: ObjectMeta{
Annotations: map[string]string{
AffinityAnnotationKey: `
{"nodeAffinity": { "requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [{
"matchExpressions": [{
"key": "foo",
"operator": "In",
"values": ["value1", "value2"]
}]
}]
}}}`,
},
},
},
expectErr: false,
},
{
pod: &Pod{
ObjectMeta: ObjectMeta{
Annotations: map[string]string{
AffinityAnnotationKey: `
{"nodeAffinity": { "requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [{
"matchExpressions": [{
"key": "foo",
`,
},
},
},
expectErr: true,
},
}
for i, tc := range testCases {
_, err := GetAffinityFromPodAnnotations(tc.pod.Annotations)
if err == nil && tc.expectErr {
t.Errorf("[%v]expected error but got none.", i)
}
if err != nil && !tc.expectErr {
t.Errorf("[%v]did not expect error but got: %v", i, err)
}
}
}

View file

@ -1,129 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package install
import (
"encoding/json"
"reflect"
"testing"
internal "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/runtime"
)
func TestResourceVersioner(t *testing.T) {
pod := internal.Pod{ObjectMeta: internal.ObjectMeta{ResourceVersion: "10"}}
version, err := accessor.ResourceVersion(&pod)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if version != "10" {
t.Errorf("unexpected version %v", version)
}
podList := internal.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: "10"}}
version, err = accessor.ResourceVersion(&podList)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if version != "10" {
t.Errorf("unexpected version %v", version)
}
}
func TestCodec(t *testing.T) {
pod := internal.Pod{}
// We do want to use package registered rather than testapi here, because we
// want to test if the package install and package registered work as expected.
data, err := runtime.Encode(internal.Codecs.LegacyCodec(registered.GroupOrDie(internal.GroupName).GroupVersion), &pod)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
other := internal.Pod{}
if err := json.Unmarshal(data, &other); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if other.APIVersion != registered.GroupOrDie(internal.GroupName).GroupVersion.Version || other.Kind != "Pod" {
t.Errorf("unexpected unmarshalled object %#v", other)
}
}
func TestInterfacesFor(t *testing.T) {
if _, err := registered.GroupOrDie(internal.GroupName).InterfacesFor(internal.SchemeGroupVersion); err == nil {
t.Fatalf("unexpected non-error: %v", err)
}
for i, version := range registered.GroupOrDie(internal.GroupName).GroupVersions {
if vi, err := registered.GroupOrDie(internal.GroupName).InterfacesFor(version); err != nil || vi == nil {
t.Fatalf("%d: unexpected result: %v", i, err)
}
}
}
func TestRESTMapper(t *testing.T) {
gv := unversioned.GroupVersion{Group: "", Version: "v1"}
rcGVK := gv.WithKind("ReplicationController")
podTemplateGVK := gv.WithKind("PodTemplate")
if gvk, err := registered.GroupOrDie(internal.GroupName).RESTMapper.KindFor(internal.SchemeGroupVersion.WithResource("replicationcontrollers")); err != nil || gvk != rcGVK {
t.Errorf("unexpected version mapping: %v %v", gvk, err)
}
if m, err := registered.GroupOrDie(internal.GroupName).RESTMapper.RESTMapping(podTemplateGVK.GroupKind(), ""); err != nil || m.GroupVersionKind != podTemplateGVK || m.Resource != "podtemplates" {
t.Errorf("unexpected version mapping: %#v %v", m, err)
}
for _, version := range registered.GroupOrDie(internal.GroupName).GroupVersions {
mapping, err := registered.GroupOrDie(internal.GroupName).RESTMapper.RESTMapping(rcGVK.GroupKind(), version.Version)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if mapping.Resource != "replicationControllers" && mapping.Resource != "replicationcontrollers" {
t.Errorf("incorrect resource name: %#v", mapping)
}
if mapping.GroupVersionKind.GroupVersion() != version {
t.Errorf("incorrect version: %v", mapping)
}
interfaces, _ := registered.GroupOrDie(internal.GroupName).InterfacesFor(version)
if mapping.ObjectConvertor != interfaces.ObjectConvertor {
t.Errorf("unexpected: %#v, expected: %#v", mapping, interfaces)
}
rc := &internal.ReplicationController{ObjectMeta: internal.ObjectMeta{Name: "foo"}}
name, err := mapping.MetadataAccessor.Name(rc)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if name != "foo" {
t.Errorf("unable to retrieve object meta with: %v", mapping.MetadataAccessor)
}
}
}
func TestUnversioned(t *testing.T) {
for _, obj := range []runtime.Object{
&unversioned.Status{},
&unversioned.ExportOptions{},
} {
if unversioned, ok := internal.Scheme.IsUnversioned(obj); !unversioned || !ok {
t.Errorf("%v is expected to be unversioned", reflect.TypeOf(obj))
}
}
}

View file

@ -43,10 +43,10 @@ func NewDefaultRESTMapper(defaultGroupVersions []unversioned.GroupVersion, inter
for _, gv := range defaultGroupVersions {
for kind, oType := range Scheme.KnownTypes(gv) {
gvk := gv.WithKind(kind)
// TODO: Remove import path prefix check.
// We check the import path prefix because we currently stuff both "api" and "extensions" objects
// TODO: Remove import path check.
// We check the import path because we currently stuff both "api" and "extensions" objects
// into the same group within Scheme since Scheme has no notion of groups yet.
if !strings.HasPrefix(oType.PkgPath(), importPathPrefix) || ignoredKinds.Has(kind) {
if !strings.Contains(oType.PkgPath(), importPathPrefix) || ignoredKinds.Has(kind) {
continue
}
scope := meta.RESTScopeNamespace

View file

@ -1,253 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package meta_test
import (
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util"
"github.com/google/gofuzz"
)
func TestIsList(t *testing.T) {
tests := []struct {
obj runtime.Object
isList bool
}{
{&api.PodList{}, true},
{&api.Pod{}, false},
}
for _, item := range tests {
if e, a := item.isList, meta.IsListType(item.obj); e != a {
t.Errorf("%v: Expected %v, got %v", reflect.TypeOf(item.obj), e, a)
}
}
}
func TestExtractList(t *testing.T) {
pl := &api.PodList{
Items: []api.Pod{
{ObjectMeta: api.ObjectMeta{Name: "1"}},
{ObjectMeta: api.ObjectMeta{Name: "2"}},
{ObjectMeta: api.ObjectMeta{Name: "3"}},
},
}
list, err := meta.ExtractList(pl)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if e, a := len(list), len(pl.Items); e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
for i := range list {
if e, a := list[i].(*api.Pod).Name, pl.Items[i].Name; e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
}
}
func TestExtractListV1(t *testing.T) {
pl := &v1.PodList{
Items: []v1.Pod{
{ObjectMeta: v1.ObjectMeta{Name: "1"}},
{ObjectMeta: v1.ObjectMeta{Name: "2"}},
{ObjectMeta: v1.ObjectMeta{Name: "3"}},
},
}
list, err := meta.ExtractList(pl)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if e, a := len(list), len(pl.Items); e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
for i := range list {
if e, a := list[i].(*v1.Pod).Name, pl.Items[i].Name; e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
}
}
func TestExtractListGeneric(t *testing.T) {
pl := &api.List{
Items: []runtime.Object{
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}},
&api.Service{ObjectMeta: api.ObjectMeta{Name: "2"}},
},
}
list, err := meta.ExtractList(pl)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if e, a := len(list), len(pl.Items); e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
if obj, ok := list[0].(*api.Pod); !ok {
t.Fatalf("Expected list[0] to be *api.Pod, it is %#v", obj)
}
if obj, ok := list[1].(*api.Service); !ok {
t.Fatalf("Expected list[1] to be *api.Service, it is %#v", obj)
}
}
func TestExtractListGenericV1(t *testing.T) {
pl := &v1.List{
Items: []runtime.RawExtension{
{RawJSON: []byte("foo")},
{RawJSON: []byte("bar")},
{Object: &v1.Pod{ObjectMeta: v1.ObjectMeta{Name: "other"}}},
},
}
list, err := meta.ExtractList(pl)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if e, a := len(list), len(pl.Items); e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
if obj, ok := list[0].(*runtime.Unknown); !ok {
t.Fatalf("Expected list[0] to be *runtime.Unknown, it is %#v", obj)
}
if obj, ok := list[1].(*runtime.Unknown); !ok {
t.Fatalf("Expected list[1] to be *runtime.Unknown, it is %#v", obj)
}
if obj, ok := list[2].(*v1.Pod); !ok {
t.Fatalf("Expected list[2] to be *runtime.Unknown, it is %#v", obj)
}
}
type fakePtrInterfaceList struct {
Items *[]runtime.Object
}
func (obj fakePtrInterfaceList) GetObjectKind() unversioned.ObjectKind {
return unversioned.EmptyObjectKind
}
func TestExtractListOfInterfacePtrs(t *testing.T) {
pl := &fakePtrInterfaceList{
Items: &[]runtime.Object{},
}
list, err := meta.ExtractList(pl)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if len(list) > 0 {
t.Fatalf("Expected empty list, got %#v", list)
}
}
type fakePtrValueList struct {
Items []*api.Pod
}
func (obj fakePtrValueList) GetObjectKind() unversioned.ObjectKind {
return unversioned.EmptyObjectKind
}
func TestExtractListOfValuePtrs(t *testing.T) {
pl := &fakePtrValueList{
Items: []*api.Pod{
{ObjectMeta: api.ObjectMeta{Name: "1"}},
{ObjectMeta: api.ObjectMeta{Name: "2"}},
},
}
list, err := meta.ExtractList(pl)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if e, a := len(list), len(pl.Items); e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
for i := range list {
if obj, ok := list[i].(*api.Pod); !ok {
t.Fatalf("Expected list[%d] to be *api.Pod, it is %#v", i, obj)
}
}
}
func TestSetList(t *testing.T) {
pl := &api.PodList{}
list := []runtime.Object{
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}},
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "2"}},
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "3"}},
}
err := meta.SetList(pl, list)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if e, a := len(list), len(pl.Items); e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
for i := range list {
if e, a := list[i].(*api.Pod).Name, pl.Items[i].Name; e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
}
}
func TestSetListToRuntimeObjectArray(t *testing.T) {
pl := &api.List{}
list := []runtime.Object{
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}},
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "2"}},
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "3"}},
}
err := meta.SetList(pl, list)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if e, a := len(list), len(pl.Items); e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
for i := range list {
if e, a := list[i], pl.Items[i]; e != a {
t.Fatalf("%d: unmatched: %s", i, util.ObjectDiff(e, a))
}
}
}
func TestSetExtractListRoundTrip(t *testing.T) {
fuzzer := fuzz.New().NilChance(0).NumElements(1, 5)
for i := 0; i < 5; i++ {
start := &api.PodList{}
fuzzer.Fuzz(&start.Items)
list, err := meta.ExtractList(start)
if err != nil {
t.Errorf("Unexpected error %v", err)
continue
}
got := &api.PodList{}
err = meta.SetList(got, list)
if err != nil {
t.Errorf("Unexpected error %v", err)
continue
}
if e, a := start, got; !reflect.DeepEqual(e, a) {
t.Fatalf("Expected %#v, got %#v", e, a)
}
}
}

View file

@ -1,778 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package meta_test
import (
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/types"
)
func TestAPIObjectMeta(t *testing.T) {
j := &api.Pod{
TypeMeta: unversioned.TypeMeta{APIVersion: "/a", Kind: "b"},
ObjectMeta: api.ObjectMeta{
Namespace: "bar",
Name: "foo",
GenerateName: "prefix",
UID: "uid",
ResourceVersion: "1",
SelfLink: "some/place/only/we/know",
Labels: map[string]string{"foo": "bar"},
Annotations: map[string]string{"x": "y"},
},
}
var _ meta.Object = &j.ObjectMeta
var _ meta.ObjectMetaAccessor = j
accessor, err := meta.Accessor(j)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if accessor != meta.Object(&j.ObjectMeta) {
t.Fatalf("should have returned the same pointer: %#v %#v", accessor, j)
}
if e, a := "bar", accessor.GetNamespace(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "foo", accessor.GetName(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "prefix", accessor.GetGenerateName(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "uid", string(accessor.GetUID()); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "1", accessor.GetResourceVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "some/place/only/we/know", accessor.GetSelfLink(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
typeAccessor, err := meta.TypeAccessor(j)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if e, a := "a", typeAccessor.GetAPIVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "b", typeAccessor.GetKind(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
accessor.SetNamespace("baz")
accessor.SetName("bar")
accessor.SetGenerateName("generate")
accessor.SetUID("other")
typeAccessor.SetAPIVersion("c")
typeAccessor.SetKind("d")
accessor.SetResourceVersion("2")
accessor.SetSelfLink("google.com")
// Prove that accessor changes the original object.
if e, a := "baz", j.Namespace; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "bar", j.Name; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "generate", j.GenerateName; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := types.UID("other"), j.UID; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "c", j.APIVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "d", j.Kind; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "2", j.ResourceVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "google.com", j.SelfLink; e != a {
t.Errorf("expected %v, got %v", e, a)
}
typeAccessor.SetAPIVersion("d")
typeAccessor.SetKind("e")
if e, a := "d", j.APIVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "e", j.Kind; e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestGenericTypeMeta(t *testing.T) {
type TypeMeta struct {
Kind string `json:"kind,omitempty"`
Namespace string `json:"namespace,omitempty"`
Name string `json:"name,omitempty"`
GenerateName string `json:"generateName,omitempty"`
UID string `json:"uid,omitempty"`
CreationTimestamp unversioned.Time `json:"creationTimestamp,omitempty"`
SelfLink string `json:"selfLink,omitempty"`
ResourceVersion string `json:"resourceVersion,omitempty"`
APIVersion string `json:"apiVersion,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Annotations map[string]string `json:"annotations,omitempty"`
}
type Object struct {
TypeMeta `json:",inline"`
}
j := Object{
TypeMeta{
Namespace: "bar",
Name: "foo",
GenerateName: "prefix",
UID: "uid",
APIVersion: "a",
Kind: "b",
ResourceVersion: "1",
SelfLink: "some/place/only/we/know",
Labels: map[string]string{"foo": "bar"},
Annotations: map[string]string{"x": "y"},
},
}
accessor, err := meta.Accessor(&j)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if e, a := "bar", accessor.GetNamespace(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "foo", accessor.GetName(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "prefix", accessor.GetGenerateName(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "uid", string(accessor.GetUID()); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "1", accessor.GetResourceVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "some/place/only/we/know", accessor.GetSelfLink(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
typeAccessor, err := meta.TypeAccessor(&j)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if e, a := "a", typeAccessor.GetAPIVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "b", typeAccessor.GetKind(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
accessor.SetNamespace("baz")
accessor.SetName("bar")
accessor.SetGenerateName("generate")
accessor.SetUID("other")
typeAccessor.SetAPIVersion("c")
typeAccessor.SetKind("d")
accessor.SetResourceVersion("2")
accessor.SetSelfLink("google.com")
// Prove that accessor changes the original object.
if e, a := "baz", j.Namespace; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "bar", j.Name; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "generate", j.GenerateName; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "other", j.UID; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "c", j.APIVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "d", j.Kind; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "2", j.ResourceVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "google.com", j.SelfLink; e != a {
t.Errorf("expected %v, got %v", e, a)
}
typeAccessor.SetAPIVersion("d")
typeAccessor.SetKind("e")
if e, a := "d", j.APIVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "e", j.Kind; e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
type InternalTypeMeta struct {
Kind string `json:"kind,omitempty"`
Namespace string `json:"namespace,omitempty"`
Name string `json:"name,omitempty"`
GenerateName string `json:"generateName,omitempty"`
UID string `json:"uid,omitempty"`
CreationTimestamp unversioned.Time `json:"creationTimestamp,omitempty"`
SelfLink string `json:"selfLink,omitempty"`
ResourceVersion string `json:"resourceVersion,omitempty"`
APIVersion string `json:"apiVersion,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Annotations map[string]string `json:"annotations,omitempty"`
}
type InternalObject struct {
TypeMeta InternalTypeMeta `json:",inline"`
}
func (obj *InternalObject) GetObjectKind() unversioned.ObjectKind { return obj }
func (obj *InternalObject) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
obj.TypeMeta.APIVersion, obj.TypeMeta.Kind = gvk.ToAPIVersionAndKind()
}
func (obj *InternalObject) GroupVersionKind() *unversioned.GroupVersionKind {
return unversioned.FromAPIVersionAndKind(obj.TypeMeta.APIVersion, obj.TypeMeta.Kind)
}
func TestGenericTypeMetaAccessor(t *testing.T) {
j := &InternalObject{
InternalTypeMeta{
Namespace: "bar",
Name: "foo",
GenerateName: "prefix",
UID: "uid",
APIVersion: "/a",
Kind: "b",
ResourceVersion: "1",
SelfLink: "some/place/only/we/know",
Labels: map[string]string{"foo": "bar"},
Annotations: map[string]string{"x": "y"},
},
}
accessor := meta.NewAccessor()
namespace, err := accessor.Namespace(j)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if e, a := "bar", namespace; e != a {
t.Errorf("expected %v, got %v", e, a)
}
name, err := accessor.Name(j)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if e, a := "foo", name; e != a {
t.Errorf("expected %v, got %v", e, a)
}
generateName, err := accessor.GenerateName(j)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if e, a := "prefix", generateName; e != a {
t.Errorf("expected %v, got %v", e, a)
}
uid, err := accessor.UID(j)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if e, a := "uid", string(uid); e != a {
t.Errorf("expected %v, got %v", e, a)
}
apiVersion, err := accessor.APIVersion(j)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if e, a := "a", apiVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
kind, err := accessor.Kind(j)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if e, a := "b", kind; e != a {
t.Errorf("expected %v, got %v", e, a)
}
rv, err := accessor.ResourceVersion(j)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if e, a := "1", rv; e != a {
t.Errorf("expected %v, got %v", e, a)
}
selfLink, err := accessor.SelfLink(j)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if e, a := "some/place/only/we/know", selfLink; e != a {
t.Errorf("expected %v, got %v", e, a)
}
labels, err := accessor.Labels(j)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if e, a := 1, len(labels); e != a {
t.Errorf("expected %v, got %v", e, a)
}
annotations, err := accessor.Annotations(j)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if e, a := 1, len(annotations); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if err := accessor.SetNamespace(j, "baz"); err != nil {
t.Errorf("unexpected error: %v", err)
}
if err := accessor.SetName(j, "bar"); err != nil {
t.Errorf("unexpected error: %v", err)
}
if err := accessor.SetGenerateName(j, "generate"); err != nil {
t.Errorf("unexpected error: %v", err)
}
if err := accessor.SetUID(j, "other"); err != nil {
t.Errorf("unexpected error: %v", err)
}
if err := accessor.SetAPIVersion(j, "c"); err != nil {
t.Errorf("unexpected error: %v", err)
}
if err := accessor.SetKind(j, "d"); err != nil {
t.Errorf("unexpected error: %v", err)
}
if err := accessor.SetResourceVersion(j, "2"); err != nil {
t.Errorf("unexpected error: %v", err)
}
if err := accessor.SetSelfLink(j, "google.com"); err != nil {
t.Errorf("unexpected error: %v", err)
}
if err := accessor.SetLabels(j, map[string]string{}); err != nil {
t.Errorf("unexpected error: %v", err)
}
var nilMap map[string]string
if err := accessor.SetAnnotations(j, nilMap); err != nil {
t.Errorf("unexpected error: %v", err)
}
// Prove that accessor changes the original object.
if e, a := "baz", j.TypeMeta.Namespace; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "bar", j.TypeMeta.Name; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "generate", j.TypeMeta.GenerateName; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "other", j.TypeMeta.UID; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "c", j.TypeMeta.APIVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "d", j.TypeMeta.Kind; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "2", j.TypeMeta.ResourceVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "google.com", j.TypeMeta.SelfLink; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := map[string]string{}, j.TypeMeta.Labels; !reflect.DeepEqual(e, a) {
t.Errorf("expected %#v, got %#v", e, a)
}
if e, a := nilMap, j.TypeMeta.Annotations; !reflect.DeepEqual(e, a) {
t.Errorf("expected %#v, got %#v", e, a)
}
}
func TestGenericObjectMeta(t *testing.T) {
type TypeMeta struct {
Kind string `json:"kind,omitempty"`
APIVersion string `json:"apiVersion,omitempty"`
}
type ObjectMeta struct {
Namespace string `json:"namespace,omitempty"`
Name string `json:"name,omitempty"`
GenerateName string `json:"generateName,omitempty"`
UID string `json:"uid,omitempty"`
CreationTimestamp unversioned.Time `json:"creationTimestamp,omitempty"`
SelfLink string `json:"selfLink,omitempty"`
ResourceVersion string `json:"resourceVersion,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Annotations map[string]string `json:"annotations,omitempty"`
}
type Object struct {
TypeMeta `json:",inline"`
ObjectMeta `json:"metadata"`
}
j := Object{
TypeMeta{
APIVersion: "a",
Kind: "b",
},
ObjectMeta{
Namespace: "bar",
Name: "foo",
GenerateName: "prefix",
UID: "uid",
ResourceVersion: "1",
SelfLink: "some/place/only/we/know",
Labels: map[string]string{"foo": "bar"},
Annotations: map[string]string{"a": "b"},
},
}
accessor, err := meta.Accessor(&j)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if e, a := "bar", accessor.GetNamespace(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "foo", accessor.GetName(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "prefix", accessor.GetGenerateName(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "uid", string(accessor.GetUID()); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "1", accessor.GetResourceVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "some/place/only/we/know", accessor.GetSelfLink(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := 1, len(accessor.GetLabels()); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := 1, len(accessor.GetAnnotations()); e != a {
t.Errorf("expected %v, got %v", e, a)
}
typeAccessor, err := meta.TypeAccessor(&j)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if e, a := "a", typeAccessor.GetAPIVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "b", typeAccessor.GetKind(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
accessor.SetNamespace("baz")
accessor.SetName("bar")
accessor.SetGenerateName("generate")
accessor.SetUID("other")
typeAccessor.SetAPIVersion("c")
typeAccessor.SetKind("d")
accessor.SetResourceVersion("2")
accessor.SetSelfLink("google.com")
accessor.SetLabels(map[string]string{"other": "label"})
accessor.SetAnnotations(map[string]string{"c": "d"})
// Prove that accessor changes the original object.
if e, a := "baz", j.Namespace; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "bar", j.Name; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "generate", j.GenerateName; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "other", j.UID; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "c", j.APIVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "d", j.Kind; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "2", j.ResourceVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "google.com", j.SelfLink; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := map[string]string{"other": "label"}, j.Labels; !reflect.DeepEqual(e, a) {
t.Errorf("expected %#v, got %#v", e, a)
}
if e, a := map[string]string{"c": "d"}, j.Annotations; !reflect.DeepEqual(e, a) {
t.Errorf("expected %#v, got %#v", e, a)
}
}
func TestGenericListMeta(t *testing.T) {
type TypeMeta struct {
Kind string `json:"kind,omitempty"`
APIVersion string `json:"apiVersion,omitempty"`
}
type ListMeta struct {
SelfLink string `json:"selfLink,omitempty"`
ResourceVersion string `json:"resourceVersion,omitempty"`
}
type Object struct {
TypeMeta `json:",inline"`
ListMeta `json:"metadata"`
}
j := Object{
TypeMeta{
APIVersion: "a",
Kind: "b",
},
ListMeta{
ResourceVersion: "1",
SelfLink: "some/place/only/we/know",
},
}
accessor, err := meta.Accessor(&j)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if e, a := "", accessor.GetName(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "", string(accessor.GetUID()); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "1", accessor.GetResourceVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "some/place/only/we/know", accessor.GetSelfLink(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
typeAccessor, err := meta.TypeAccessor(&j)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if e, a := "a", typeAccessor.GetAPIVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "b", typeAccessor.GetKind(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
accessor.SetName("bar")
accessor.SetUID("other")
typeAccessor.SetAPIVersion("c")
typeAccessor.SetKind("d")
accessor.SetResourceVersion("2")
accessor.SetSelfLink("google.com")
// Prove that accessor changes the original object.
if e, a := "c", j.APIVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "d", j.Kind; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "2", j.ResourceVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "google.com", j.SelfLink; e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
type MyAPIObject struct {
TypeMeta InternalTypeMeta `json:",inline"`
}
func (obj *MyAPIObject) GetObjectKind() unversioned.ObjectKind { return obj }
func (obj *MyAPIObject) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
obj.TypeMeta.APIVersion, obj.TypeMeta.Kind = gvk.ToAPIVersionAndKind()
}
func (obj *MyAPIObject) GroupVersionKind() *unversioned.GroupVersionKind {
return unversioned.FromAPIVersionAndKind(obj.TypeMeta.APIVersion, obj.TypeMeta.Kind)
}
type MyIncorrectlyMarkedAsAPIObject struct{}
func (obj *MyIncorrectlyMarkedAsAPIObject) GetObjectKind() unversioned.ObjectKind {
return unversioned.EmptyObjectKind
}
func TestResourceVersionerOfAPI(t *testing.T) {
type T struct {
runtime.Object
Expected string
}
testCases := map[string]T{
"empty api object": {&MyAPIObject{}, ""},
"api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"},
"pointer to api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"},
}
versioning := meta.NewAccessor()
for key, testCase := range testCases {
actual, err := versioning.ResourceVersion(testCase.Object)
if err != nil {
t.Errorf("%s: unexpected error %#v", key, err)
}
if actual != testCase.Expected {
t.Errorf("%s: expected %v, got %v", key, testCase.Expected, actual)
}
}
failingCases := map[string]struct {
runtime.Object
Expected string
}{
"not a valid object to try": {&MyIncorrectlyMarkedAsAPIObject{}, "1"},
}
for key, testCase := range failingCases {
_, err := versioning.ResourceVersion(testCase.Object)
if err == nil {
t.Errorf("%s: expected error, got nil", key)
}
}
setCases := map[string]struct {
runtime.Object
Expected string
}{
"pointer to api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"},
}
for key, testCase := range setCases {
if err := versioning.SetResourceVersion(testCase.Object, "5"); err != nil {
t.Errorf("%s: unexpected error %#v", key, err)
}
actual, err := versioning.ResourceVersion(testCase.Object)
if err != nil {
t.Errorf("%s: unexpected error %#v", key, err)
}
if actual != "5" {
t.Errorf("%s: expected %v, got %v", key, "5", actual)
}
}
}
func TestTypeMetaSelfLinker(t *testing.T) {
table := map[string]struct {
obj runtime.Object
expect string
try string
succeed bool
}{
"normal": {
obj: &MyAPIObject{TypeMeta: InternalTypeMeta{SelfLink: "foobar"}},
expect: "foobar",
try: "newbar",
succeed: true,
},
"fail": {
obj: &MyIncorrectlyMarkedAsAPIObject{},
succeed: false,
},
}
linker := runtime.SelfLinker(meta.NewAccessor())
for name, item := range table {
got, err := linker.SelfLink(item.obj)
if e, a := item.succeed, err == nil; e != a {
t.Errorf("%v: expected %v, got %v", name, e, a)
}
if e, a := item.expect, got; item.succeed && e != a {
t.Errorf("%v: expected %v, got %v", name, e, a)
}
err = linker.SetSelfLink(item.obj, item.try)
if e, a := item.succeed, err == nil; e != a {
t.Errorf("%v: expected %v, got %v", name, e, a)
}
if item.succeed {
got, err := linker.SelfLink(item.obj)
if err != nil {
t.Errorf("%v: expected no err, got %v", name, err)
}
if e, a := item.try, got; e != a {
t.Errorf("%v: expected %v, got %v", name, e, a)
}
}
}
}
// BenchmarkAccessorSetFastPath shows the interface fast path
func BenchmarkAccessorSetFastPath(b *testing.B) {
obj := &api.Pod{
TypeMeta: unversioned.TypeMeta{APIVersion: "/a", Kind: "b"},
ObjectMeta: api.ObjectMeta{
Namespace: "bar",
Name: "foo",
GenerateName: "prefix",
UID: "uid",
ResourceVersion: "1",
SelfLink: "some/place/only/we/know",
Labels: map[string]string{"foo": "bar"},
Annotations: map[string]string{"x": "y"},
},
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
acc, err := meta.Accessor(obj)
if err != nil {
b.Fatal(err)
}
acc.SetNamespace("something")
}
b.StopTimer()
}
// BenchmarkAccessorSetReflection provides a baseline for accessor performance
func BenchmarkAccessorSetReflection(b *testing.B) {
obj := &InternalObject{
InternalTypeMeta{
Namespace: "bar",
Name: "foo",
GenerateName: "prefix",
UID: "uid",
APIVersion: "a",
Kind: "b",
ResourceVersion: "1",
SelfLink: "some/place/only/we/know",
Labels: map[string]string{"foo": "bar"},
Annotations: map[string]string{"x": "y"},
},
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
acc, err := meta.Accessor(obj)
if err != nil {
b.Fatal(err)
}
acc.SetNamespace("something")
}
b.StopTimer()
}

View file

@ -21,6 +21,7 @@ import (
"strings"
"k8s.io/kubernetes/pkg/api/unversioned"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
)
// MultiRESTMapper is a wrapper for multiple RESTMappers.
@ -50,72 +51,144 @@ func (m MultiRESTMapper) ResourceSingularizer(resource string) (singular string,
}
func (m MultiRESTMapper) ResourcesFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) {
allGVRs := []unversioned.GroupVersionResource{}
for _, t := range m {
gvrs, err := t.ResourcesFor(resource)
// ignore "no match" errors, but any other error percolates back up
if !IsNoResourceMatchError(err) {
return gvrs, err
if IsNoResourceMatchError(err) {
continue
}
if err != nil {
return nil, err
}
// walk the existing values to de-dup
for _, curr := range gvrs {
found := false
for _, existing := range allGVRs {
if curr == existing {
found = true
break
}
}
if !found {
allGVRs = append(allGVRs, curr)
}
}
}
return nil, &NoResourceMatchError{PartialResource: resource}
if len(allGVRs) == 0 {
return nil, &NoResourceMatchError{PartialResource: resource}
}
return allGVRs, nil
}
// KindsFor provides the Kind mappings for the REST resources. This implementation supports multiple REST schemas and returns
// the first match.
func (m MultiRESTMapper) KindsFor(resource unversioned.GroupVersionResource) (gvk []unversioned.GroupVersionKind, err error) {
allGVKs := []unversioned.GroupVersionKind{}
for _, t := range m {
gvks, err := t.KindsFor(resource)
// ignore "no match" errors, but any other error percolates back up
if !IsNoResourceMatchError(err) {
return gvks, err
if IsNoResourceMatchError(err) {
continue
}
if err != nil {
return nil, err
}
// walk the existing values to de-dup
for _, curr := range gvks {
found := false
for _, existing := range allGVKs {
if curr == existing {
found = true
break
}
}
if !found {
allGVKs = append(allGVKs, curr)
}
}
}
return nil, &NoResourceMatchError{PartialResource: resource}
if len(allGVKs) == 0 {
return nil, &NoResourceMatchError{PartialResource: resource}
}
return allGVKs, nil
}
func (m MultiRESTMapper) ResourceFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) {
for _, t := range m {
gvr, err := t.ResourceFor(resource)
// ignore "no match" errors, but any other error percolates back up
if !IsNoResourceMatchError(err) {
return gvr, err
}
resources, err := m.ResourcesFor(resource)
if err != nil {
return unversioned.GroupVersionResource{}, err
}
return unversioned.GroupVersionResource{}, &NoResourceMatchError{PartialResource: resource}
if len(resources) == 1 {
return resources[0], nil
}
return unversioned.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: resource, MatchingResources: resources}
}
// KindsFor provides the Kind mapping for the REST resources. This implementation supports multiple REST schemas and returns
// the first match.
func (m MultiRESTMapper) KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) {
for _, t := range m {
gvk, err := t.KindFor(resource)
// ignore "no match" errors, but any other error percolates back up
if !IsNoResourceMatchError(err) {
return gvk, err
}
kinds, err := m.KindsFor(resource)
if err != nil {
return unversioned.GroupVersionKind{}, err
}
return unversioned.GroupVersionKind{}, &NoResourceMatchError{PartialResource: resource}
if len(kinds) == 1 {
return kinds[0], nil
}
return unversioned.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: resource, MatchingKinds: kinds}
}
// RESTMapping provides the REST mapping for the resource based on the
// kind and version. This implementation supports multiple REST schemas and
// return the first match.
func (m MultiRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (mapping *RESTMapping, err error) {
func (m MultiRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (*RESTMapping, error) {
allMappings := []*RESTMapping{}
errors := []error{}
for _, t := range m {
mapping, err = t.RESTMapping(gk, versions...)
if err == nil {
return
currMapping, err := t.RESTMapping(gk, versions...)
// ignore "no match" errors, but any other error percolates back up
if IsNoResourceMatchError(err) {
continue
}
if err != nil {
errors = append(errors, err)
continue
}
allMappings = append(allMappings, currMapping)
}
return
// if we got exactly one mapping, then use it even if other requested failed
if len(allMappings) == 1 {
return allMappings[0], nil
}
if len(errors) > 0 {
return nil, utilerrors.NewAggregate(errors)
}
if len(allMappings) == 0 {
return nil, fmt.Errorf("no match found for %v in %v", gk, versions)
}
return nil, fmt.Errorf("multiple matches found for %v in %v", gk, versions)
}
// AliasesForResource finds the first alias response for the provided mappers.
func (m MultiRESTMapper) AliasesForResource(alias string) (aliases []string, ok bool) {
func (m MultiRESTMapper) AliasesForResource(alias string) ([]string, bool) {
allAliases := []string{}
handled := false
for _, t := range m {
if aliases, ok = t.AliasesForResource(alias); ok {
return
if currAliases, currOk := t.AliasesForResource(alias); currOk {
allAliases = append(allAliases, currAliases...)
handled = true
}
}
return nil, false
return allAliases, handled
}

View file

@ -1,238 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package meta
import (
"errors"
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api/unversioned"
)
func TestMultiRESTMapperResourceForErrorHandling(t *testing.T) {
tcs := []struct {
name string
mapper MultiRESTMapper
input unversioned.GroupVersionResource
result unversioned.GroupVersionResource
err error
}{
{
name: "empty",
mapper: MultiRESTMapper{},
input: unversioned.GroupVersionResource{Resource: "foo"},
result: unversioned.GroupVersionResource{},
err: &NoResourceMatchError{PartialResource: unversioned.GroupVersionResource{Resource: "foo"}},
},
{
name: "ignore not found",
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: unversioned.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
input: unversioned.GroupVersionResource{Resource: "foo"},
result: unversioned.GroupVersionResource{},
err: &NoResourceMatchError{PartialResource: unversioned.GroupVersionResource{Resource: "foo"}},
},
{
name: "accept first failure",
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{resourceFor: unversioned.GroupVersionResource{Resource: "unused"}}},
input: unversioned.GroupVersionResource{Resource: "foo"},
result: unversioned.GroupVersionResource{},
err: errors.New("fail on this"),
},
}
for _, tc := range tcs {
actualResult, actualErr := tc.mapper.ResourceFor(tc.input)
if e, a := tc.result, actualResult; e != a {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
if e, a := tc.err.Error(), actualErr.Error(); e != a {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
}
}
func TestMultiRESTMapperResourcesForErrorHandling(t *testing.T) {
tcs := []struct {
name string
mapper MultiRESTMapper
input unversioned.GroupVersionResource
result []unversioned.GroupVersionResource
err error
}{
{
name: "empty",
mapper: MultiRESTMapper{},
input: unversioned.GroupVersionResource{Resource: "foo"},
result: nil,
err: &NoResourceMatchError{PartialResource: unversioned.GroupVersionResource{Resource: "foo"}},
},
{
name: "ignore not found",
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: unversioned.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
input: unversioned.GroupVersionResource{Resource: "foo"},
result: nil,
err: &NoResourceMatchError{PartialResource: unversioned.GroupVersionResource{Resource: "foo"}},
},
{
name: "accept first failure",
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{resourcesFor: []unversioned.GroupVersionResource{{Resource: "unused"}}}},
input: unversioned.GroupVersionResource{Resource: "foo"},
result: nil,
err: errors.New("fail on this"),
},
}
for _, tc := range tcs {
actualResult, actualErr := tc.mapper.ResourcesFor(tc.input)
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
if e, a := tc.err.Error(), actualErr.Error(); e != a {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
}
}
func TestMultiRESTMapperKindsForErrorHandling(t *testing.T) {
tcs := []struct {
name string
mapper MultiRESTMapper
input unversioned.GroupVersionResource
result []unversioned.GroupVersionKind
err error
}{
{
name: "empty",
mapper: MultiRESTMapper{},
input: unversioned.GroupVersionResource{Resource: "foo"},
result: nil,
err: &NoResourceMatchError{PartialResource: unversioned.GroupVersionResource{Resource: "foo"}},
},
{
name: "ignore not found",
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: unversioned.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
input: unversioned.GroupVersionResource{Resource: "foo"},
result: nil,
err: &NoResourceMatchError{PartialResource: unversioned.GroupVersionResource{Resource: "foo"}},
},
{
name: "accept first failure",
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{kindsFor: []unversioned.GroupVersionKind{{Kind: "unused"}}}},
input: unversioned.GroupVersionResource{Resource: "foo"},
result: nil,
err: errors.New("fail on this"),
},
}
for _, tc := range tcs {
actualResult, actualErr := tc.mapper.KindsFor(tc.input)
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
if e, a := tc.err.Error(), actualErr.Error(); e != a {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
}
}
func TestMultiRESTMapperKindForErrorHandling(t *testing.T) {
tcs := []struct {
name string
mapper MultiRESTMapper
input unversioned.GroupVersionResource
result unversioned.GroupVersionKind
err error
}{
{
name: "empty",
mapper: MultiRESTMapper{},
input: unversioned.GroupVersionResource{Resource: "foo"},
result: unversioned.GroupVersionKind{},
err: &NoResourceMatchError{PartialResource: unversioned.GroupVersionResource{Resource: "foo"}},
},
{
name: "ignore not found",
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: unversioned.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
input: unversioned.GroupVersionResource{Resource: "foo"},
result: unversioned.GroupVersionKind{},
err: &NoResourceMatchError{PartialResource: unversioned.GroupVersionResource{Resource: "foo"}},
},
{
name: "accept first failure",
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{kindFor: unversioned.GroupVersionKind{Kind: "unused"}}},
input: unversioned.GroupVersionResource{Resource: "foo"},
result: unversioned.GroupVersionKind{},
err: errors.New("fail on this"),
},
}
for _, tc := range tcs {
actualResult, actualErr := tc.mapper.KindFor(tc.input)
if e, a := tc.result, actualResult; e != a {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
if e, a := tc.err.Error(), actualErr.Error(); e != a {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
}
}
type fixedRESTMapper struct {
resourcesFor []unversioned.GroupVersionResource
kindsFor []unversioned.GroupVersionKind
resourceFor unversioned.GroupVersionResource
kindFor unversioned.GroupVersionKind
err error
}
func (m fixedRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
return "", m.err
}
func (m fixedRESTMapper) ResourcesFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) {
return m.resourcesFor, m.err
}
func (m fixedRESTMapper) KindsFor(resource unversioned.GroupVersionResource) (gvk []unversioned.GroupVersionKind, err error) {
return m.kindsFor, m.err
}
func (m fixedRESTMapper) ResourceFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) {
return m.resourceFor, m.err
}
func (m fixedRESTMapper) KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) {
return m.kindFor, m.err
}
func (m fixedRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (mapping *RESTMapping, err error) {
return nil, m.err
}
func (m fixedRESTMapper) AliasesForResource(alias string) (aliases []string, ok bool) {
return nil, false
}
func (m fixedRESTMapper) ResourceIsValid(resource unversioned.GroupVersionResource) bool {
return false
}

View file

@ -0,0 +1,173 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package meta
import (
"fmt"
"k8s.io/kubernetes/pkg/api/unversioned"
)
const (
AnyGroup = "*"
AnyVersion = "*"
AnyResource = "*"
AnyKind = "*"
)
// PriorityRESTMapper is a wrapper for automatically choosing a particular Resource or Kind
// when multiple matches are possible
type PriorityRESTMapper struct {
// Delegate is the RESTMapper to use to locate all the Kind and Resource matches
Delegate RESTMapper
// ResourcePriority is a list of priority patterns to apply to matching resources.
// The list of all matching resources is narrowed based on the patterns until only one remains.
// A pattern with no matches is skipped. A pattern with more than one match uses its
// matches as the list to continue matching against.
ResourcePriority []unversioned.GroupVersionResource
// KindPriority is a list of priority patterns to apply to matching kinds.
// The list of all matching kinds is narrowed based on the patterns until only one remains.
// A pattern with no matches is skipped. A pattern with more than one match uses its
// matches as the list to continue matching against.
KindPriority []unversioned.GroupVersionKind
}
func (m PriorityRESTMapper) String() string {
return fmt.Sprintf("PriorityRESTMapper{\n\t%v\n\t%v\n\t%v\n}", m.ResourcePriority, m.KindPriority, m.Delegate)
}
// ResourceFor finds all resources, then passes them through the ResourcePriority patterns to find a single matching hit.
func (m PriorityRESTMapper) ResourceFor(partiallySpecifiedResource unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) {
originalGVRs, err := m.Delegate.ResourcesFor(partiallySpecifiedResource)
if err != nil {
return unversioned.GroupVersionResource{}, err
}
if len(originalGVRs) == 1 {
return originalGVRs[0], nil
}
remainingGVRs := append([]unversioned.GroupVersionResource{}, originalGVRs...)
for _, pattern := range m.ResourcePriority {
matchedGVRs := []unversioned.GroupVersionResource{}
for _, gvr := range remainingGVRs {
if resourceMatches(pattern, gvr) {
matchedGVRs = append(matchedGVRs, gvr)
}
}
switch len(matchedGVRs) {
case 0:
// if you have no matches, then nothing matched this pattern just move to the next
continue
case 1:
// one match, return
return matchedGVRs[0], nil
default:
// more than one match, use the matched hits as the list moving to the next pattern.
// this way you can have a series of selection criteria
remainingGVRs = matchedGVRs
}
}
return unversioned.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: partiallySpecifiedResource, MatchingResources: originalGVRs}
}
// KindFor finds all kinds, then passes them through the KindPriority patterns to find a single matching hit.
func (m PriorityRESTMapper) KindFor(partiallySpecifiedResource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) {
originalGVKs, err := m.Delegate.KindsFor(partiallySpecifiedResource)
if err != nil {
return unversioned.GroupVersionKind{}, err
}
if len(originalGVKs) == 1 {
return originalGVKs[0], nil
}
remainingGVKs := append([]unversioned.GroupVersionKind{}, originalGVKs...)
for _, pattern := range m.KindPriority {
matchedGVKs := []unversioned.GroupVersionKind{}
for _, gvr := range remainingGVKs {
if kindMatches(pattern, gvr) {
matchedGVKs = append(matchedGVKs, gvr)
}
}
switch len(matchedGVKs) {
case 0:
// if you have no matches, then nothing matched this pattern just move to the next
continue
case 1:
// one match, return
return matchedGVKs[0], nil
default:
// more than one match, use the matched hits as the list moving to the next pattern.
// this way you can have a series of selection criteria
remainingGVKs = matchedGVKs
}
}
return unversioned.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: partiallySpecifiedResource, MatchingKinds: originalGVKs}
}
func resourceMatches(pattern unversioned.GroupVersionResource, resource unversioned.GroupVersionResource) bool {
if pattern.Group != AnyGroup && pattern.Group != resource.Group {
return false
}
if pattern.Version != AnyVersion && pattern.Version != resource.Version {
return false
}
if pattern.Resource != AnyResource && pattern.Resource != resource.Resource {
return false
}
return true
}
func kindMatches(pattern unversioned.GroupVersionKind, kind unversioned.GroupVersionKind) bool {
if pattern.Group != AnyGroup && pattern.Group != kind.Group {
return false
}
if pattern.Version != AnyVersion && pattern.Version != kind.Version {
return false
}
if pattern.Kind != AnyKind && pattern.Kind != kind.Kind {
return false
}
return true
}
func (m PriorityRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (mapping *RESTMapping, err error) {
return m.Delegate.RESTMapping(gk, versions...)
}
func (m PriorityRESTMapper) AliasesForResource(alias string) (aliases []string, ok bool) {
return m.Delegate.AliasesForResource(alias)
}
func (m PriorityRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
return m.Delegate.ResourceSingularizer(resource)
}
func (m PriorityRESTMapper) ResourcesFor(partiallySpecifiedResource unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) {
return m.Delegate.ResourcesFor(partiallySpecifiedResource)
}
func (m PriorityRESTMapper) KindsFor(partiallySpecifiedResource unversioned.GroupVersionResource) (gvk []unversioned.GroupVersionKind, err error) {
return m.Delegate.KindsFor(partiallySpecifiedResource)
}

View file

@ -24,7 +24,6 @@ import (
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/sets"
)
// Implements RESTScope interface
@ -330,23 +329,8 @@ func (m *DefaultRESTMapper) KindFor(resource unversioned.GroupVersionResource) (
if err != nil {
return unversioned.GroupVersionKind{}, err
}
// TODO for each group, choose the most preferred (first) version. This keeps us consistent with code today.
// eventually, we'll need a RESTMapper that is aware of what's available server-side and deconflicts that with
// user preferences
oneKindPerGroup := []unversioned.GroupVersionKind{}
groupsAdded := sets.String{}
for _, kind := range kinds {
if groupsAdded.Has(kind.Group) {
continue
}
oneKindPerGroup = append(oneKindPerGroup, kind)
groupsAdded.Insert(kind.Group)
}
if len(oneKindPerGroup) == 1 {
return oneKindPerGroup[0], nil
if len(kinds) == 1 {
return kinds[0], nil
}
return unversioned.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: resource, MatchingKinds: kinds}

View file

@ -1,550 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package meta
import (
"errors"
"reflect"
"strings"
"testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
)
type fakeConvertor struct{}
func (fakeConvertor) Convert(in, out interface{}) error {
return nil
}
func (fakeConvertor) ConvertToVersion(in runtime.Object, _ string) (runtime.Object, error) {
return in, nil
}
func (fakeConvertor) ConvertFieldLabel(version, kind, label, value string) (string, string, error) {
return label, value, nil
}
var validAccessor = resourceAccessor{}
var validConvertor = fakeConvertor{}
func fakeInterfaces(version unversioned.GroupVersion) (*VersionInterfaces, error) {
return &VersionInterfaces{ObjectConvertor: validConvertor, MetadataAccessor: validAccessor}, nil
}
var unmatchedErr = errors.New("no version")
func unmatchedVersionInterfaces(version unversioned.GroupVersion) (*VersionInterfaces, error) {
return nil, unmatchedErr
}
func TestRESTMapperVersionAndKindForResource(t *testing.T) {
testGroup := "test.group"
testVersion := "test"
testGroupVersion := unversioned.GroupVersion{Group: testGroup, Version: testVersion}
testCases := []struct {
Resource unversioned.GroupVersionResource
GroupVersionToRegister unversioned.GroupVersion
ExpectedGVK unversioned.GroupVersionKind
Err bool
}{
{Resource: unversioned.GroupVersionResource{Resource: "internalobjec"}, Err: true},
{Resource: unversioned.GroupVersionResource{Resource: "internalObjec"}, Err: true},
{Resource: unversioned.GroupVersionResource{Resource: "internalobject"}, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
{Resource: unversioned.GroupVersionResource{Resource: "internalobjects"}, ExpectedGVK: testGroupVersion.WithKind("InternalObject")},
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{testGroupVersion}, fakeInterfaces)
if len(testCase.ExpectedGVK.Kind) != 0 {
mapper.Add(testCase.ExpectedGVK, RESTScopeNamespace)
}
actualGVK, err := mapper.KindFor(testCase.Resource)
hasErr := err != nil
if hasErr != testCase.Err {
t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err)
continue
}
if err != nil {
continue
}
if actualGVK != testCase.ExpectedGVK {
t.Errorf("%d: unexpected version and kind: e=%s a=%s", i, testCase.ExpectedGVK, actualGVK)
}
}
}
func TestRESTMapperGroupForResource(t *testing.T) {
testCases := []struct {
Resource unversioned.GroupVersionResource
GroupVersionKind unversioned.GroupVersionKind
Err bool
}{
{Resource: unversioned.GroupVersionResource{Resource: "myObject"}, GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
{Resource: unversioned.GroupVersionResource{Resource: "myobject"}, GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi2", Version: "test", Kind: "MyObject"}},
{Resource: unversioned.GroupVersionResource{Resource: "myObje"}, Err: true, GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
{Resource: unversioned.GroupVersionResource{Resource: "myobje"}, Err: true, GroupVersionKind: unversioned.GroupVersionKind{Group: "testapi", Version: "test", Kind: "MyObject"}},
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{testCase.GroupVersionKind.GroupVersion()}, fakeInterfaces)
mapper.Add(testCase.GroupVersionKind, RESTScopeNamespace)
actualGVK, err := mapper.KindFor(testCase.Resource)
if testCase.Err {
if err == nil {
t.Errorf("%d: expected error", i)
}
} else if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
} else if actualGVK != testCase.GroupVersionKind {
t.Errorf("%d: expected group %q, got %q", i, testCase.GroupVersionKind, actualGVK)
}
}
}
func TestRESTMapperKindsFor(t *testing.T) {
testCases := []struct {
Name string
PreferredOrder []unversioned.GroupVersion
KindsToRegister []unversioned.GroupVersionKind
PartialResourceToRequest unversioned.GroupVersionResource
ExpectedKinds []unversioned.GroupVersionKind
ExpectedKindErr string
}{
{
Name: "ambiguous groups, with preference order",
PreferredOrder: []unversioned.GroupVersion{
{Group: "second-group", Version: "first-version"},
{Group: "first-group", Version: "first-version"},
},
KindsToRegister: []unversioned.GroupVersionKind{
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
},
PartialResourceToRequest: unversioned.GroupVersionResource{Resource: "my-kinds"},
ExpectedKinds: []unversioned.GroupVersionKind{
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
},
ExpectedKindErr: " matches multiple kinds ",
},
{
Name: "ambiguous groups, with explicit group match",
PreferredOrder: []unversioned.GroupVersion{
{Group: "second-group", Version: "first-version"},
{Group: "first-group", Version: "first-version"},
},
KindsToRegister: []unversioned.GroupVersionKind{
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
},
PartialResourceToRequest: unversioned.GroupVersionResource{Group: "first-group", Resource: "my-kinds"},
ExpectedKinds: []unversioned.GroupVersionKind{
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
},
},
{
Name: "ambiguous groups, with ambiguous version match",
PreferredOrder: []unversioned.GroupVersion{
{Group: "first-group", Version: "first-version"},
{Group: "second-group", Version: "first-version"},
},
KindsToRegister: []unversioned.GroupVersionKind{
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
},
PartialResourceToRequest: unversioned.GroupVersionResource{Version: "first-version", Resource: "my-kinds"},
ExpectedKinds: []unversioned.GroupVersionKind{
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
},
ExpectedKindErr: " matches multiple kinds ",
},
}
for _, testCase := range testCases {
tcName := testCase.Name
mapper := NewDefaultRESTMapper(testCase.PreferredOrder, fakeInterfaces)
for _, kind := range testCase.KindsToRegister {
mapper.Add(kind, RESTScopeNamespace)
}
actualKinds, err := mapper.KindsFor(testCase.PartialResourceToRequest)
if err != nil {
t.Errorf("%s: unexpected error: %v", tcName, err)
continue
}
if !reflect.DeepEqual(testCase.ExpectedKinds, actualKinds) {
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKinds, actualKinds)
}
singleKind, err := mapper.KindFor(testCase.PartialResourceToRequest)
if err == nil && len(testCase.ExpectedKindErr) != 0 {
t.Errorf("%s: expected error: %v", tcName, testCase.ExpectedKindErr)
continue
}
if err != nil {
if len(testCase.ExpectedKindErr) == 0 {
t.Errorf("%s: unexpected error: %v", tcName, err)
continue
} else {
if !strings.Contains(err.Error(), testCase.ExpectedKindErr) {
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKindErr, err)
continue
}
}
} else {
if testCase.ExpectedKinds[0] != singleKind {
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedKinds[0], singleKind)
}
}
}
}
func TestRESTMapperResourcesFor(t *testing.T) {
testCases := []struct {
Name string
PreferredOrder []unversioned.GroupVersion
KindsToRegister []unversioned.GroupVersionKind
PluralPartialResourceToRequest unversioned.GroupVersionResource
SingularPartialResourceToRequest unversioned.GroupVersionResource
ExpectedResources []unversioned.GroupVersionResource
ExpectedResourceErr string
}{
{
Name: "ambiguous groups, with preference order",
PreferredOrder: []unversioned.GroupVersion{
{Group: "second-group", Version: "first-version"},
{Group: "first-group", Version: "first-version"},
},
KindsToRegister: []unversioned.GroupVersionKind{
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
},
PluralPartialResourceToRequest: unversioned.GroupVersionResource{Resource: "my-kinds"},
SingularPartialResourceToRequest: unversioned.GroupVersionResource{Resource: "my-kind"},
ExpectedResources: []unversioned.GroupVersionResource{
{Group: "second-group", Version: "first-version", Resource: "my-kinds"},
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
},
ExpectedResourceErr: " matches multiple resources ",
},
{
Name: "ambiguous groups, with explicit group match",
PreferredOrder: []unversioned.GroupVersion{
{Group: "second-group", Version: "first-version"},
{Group: "first-group", Version: "first-version"},
},
KindsToRegister: []unversioned.GroupVersionKind{
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
},
PluralPartialResourceToRequest: unversioned.GroupVersionResource{Group: "first-group", Resource: "my-kinds"},
SingularPartialResourceToRequest: unversioned.GroupVersionResource{Group: "first-group", Resource: "my-kind"},
ExpectedResources: []unversioned.GroupVersionResource{
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
},
},
{
Name: "ambiguous groups, with ambiguous version match",
PreferredOrder: []unversioned.GroupVersion{
{Group: "first-group", Version: "first-version"},
{Group: "second-group", Version: "first-version"},
},
KindsToRegister: []unversioned.GroupVersionKind{
{Group: "first-group", Version: "first-version", Kind: "my-kind"},
{Group: "first-group", Version: "first-version", Kind: "your-kind"},
{Group: "second-group", Version: "first-version", Kind: "my-kind"},
{Group: "second-group", Version: "first-version", Kind: "your-kind"},
},
PluralPartialResourceToRequest: unversioned.GroupVersionResource{Version: "first-version", Resource: "my-kinds"},
SingularPartialResourceToRequest: unversioned.GroupVersionResource{Version: "first-version", Resource: "my-kind"},
ExpectedResources: []unversioned.GroupVersionResource{
{Group: "first-group", Version: "first-version", Resource: "my-kinds"},
{Group: "second-group", Version: "first-version", Resource: "my-kinds"},
},
ExpectedResourceErr: " matches multiple resources ",
},
}
for _, testCase := range testCases {
tcName := testCase.Name
for _, partialResource := range []unversioned.GroupVersionResource{testCase.PluralPartialResourceToRequest, testCase.SingularPartialResourceToRequest} {
mapper := NewDefaultRESTMapper(testCase.PreferredOrder, fakeInterfaces)
for _, kind := range testCase.KindsToRegister {
mapper.Add(kind, RESTScopeNamespace)
}
actualResources, err := mapper.ResourcesFor(partialResource)
if err != nil {
t.Errorf("%s: unexpected error: %v", tcName, err)
continue
}
if !reflect.DeepEqual(testCase.ExpectedResources, actualResources) {
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResources, actualResources)
}
singleResource, err := mapper.ResourceFor(partialResource)
if err == nil && len(testCase.ExpectedResourceErr) != 0 {
t.Errorf("%s: expected error: %v", tcName, testCase.ExpectedResourceErr)
continue
}
if err != nil {
if len(testCase.ExpectedResourceErr) == 0 {
t.Errorf("%s: unexpected error: %v", tcName, err)
continue
} else {
if !strings.Contains(err.Error(), testCase.ExpectedResourceErr) {
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResourceErr, err)
continue
}
}
} else {
if testCase.ExpectedResources[0] != singleResource {
t.Errorf("%s: expected %v, got %v", tcName, testCase.ExpectedResources[0], singleResource)
}
}
}
}
}
func TestKindToResource(t *testing.T) {
testCases := []struct {
Kind string
Plural, Singular string
}{
{Kind: "Pod", Plural: "pods", Singular: "pod"},
{Kind: "ReplicationController", Plural: "replicationcontrollers", Singular: "replicationcontroller"},
// Add "ies" when ending with "y"
{Kind: "ImageRepository", Plural: "imagerepositories", Singular: "imagerepository"},
// Add "es" when ending with "s"
{Kind: "miss", Plural: "misses", Singular: "miss"},
// Add "s" otherwise
{Kind: "lowercase", Plural: "lowercases", Singular: "lowercase"},
}
for i, testCase := range testCases {
version := unversioned.GroupVersion{}
plural, singular := KindToResource(version.WithKind(testCase.Kind))
if singular != version.WithResource(testCase.Singular) || plural != version.WithResource(testCase.Plural) {
t.Errorf("%d: unexpected plural and singular: %v %v", i, plural, singular)
}
}
}
func TestRESTMapperResourceSingularizer(t *testing.T) {
testGroupVersion := unversioned.GroupVersion{Group: "tgroup", Version: "test"}
testCases := []struct {
Kind string
Plural string
Singular string
}{
{Kind: "Pod", Plural: "pods", Singular: "pod"},
{Kind: "ReplicationController", Plural: "replicationcontrollers", Singular: "replicationcontroller"},
{Kind: "ImageRepository", Plural: "imagerepositories", Singular: "imagerepository"},
{Kind: "Status", Plural: "statuses", Singular: "status"},
{Kind: "lowercase", Plural: "lowercases", Singular: "lowercase"},
// TODO this test is broken. This updates to reflect actual behavior. Kinds are expected to be singular
// old (incorrect), coment: Don't add extra s if the original object is already plural
{Kind: "lowercases", Plural: "lowercaseses", Singular: "lowercases"},
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{testGroupVersion}, fakeInterfaces)
// create singular/plural mapping
mapper.Add(testGroupVersion.WithKind(testCase.Kind), RESTScopeNamespace)
singular, err := mapper.ResourceSingularizer(testCase.Plural)
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
}
if singular != testCase.Singular {
t.Errorf("%d: mismatched singular: got %v, expected %v", i, singular, testCase.Singular)
}
}
}
func TestRESTMapperRESTMapping(t *testing.T) {
testGroup := "tgroup"
testGroupVersion := unversioned.GroupVersion{Group: testGroup, Version: "test"}
internalGroupVersion := unversioned.GroupVersion{Group: testGroup, Version: "test"}
testCases := []struct {
Kind string
APIGroupVersions []unversioned.GroupVersion
DefaultVersions []unversioned.GroupVersion
Resource string
ExpectedGroupVersion *unversioned.GroupVersion
Err bool
}{
{Kind: "Unknown", Err: true},
{Kind: "InternalObject", Err: true},
{DefaultVersions: []unversioned.GroupVersion{testGroupVersion}, Kind: "Unknown", Err: true},
{DefaultVersions: []unversioned.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []unversioned.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
{DefaultVersions: []unversioned.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []unversioned.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
{DefaultVersions: []unversioned.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []unversioned.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
{DefaultVersions: []unversioned.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []unversioned.GroupVersion{}, Resource: "internalobjects", ExpectedGroupVersion: &unversioned.GroupVersion{Group: testGroup, Version: "test"}},
{DefaultVersions: []unversioned.GroupVersion{testGroupVersion}, Kind: "InternalObject", APIGroupVersions: []unversioned.GroupVersion{{Group: testGroup, Version: "test"}}, Resource: "internalobjects"},
// TODO: add test for a resource that exists in one version but not another
}
for i, testCase := range testCases {
mapper := NewDefaultRESTMapper(testCase.DefaultVersions, fakeInterfaces)
mapper.Add(internalGroupVersion.WithKind("InternalObject"), RESTScopeNamespace)
preferredVersions := []string{}
for _, gv := range testCase.APIGroupVersions {
preferredVersions = append(preferredVersions, gv.Version)
}
gk := unversioned.GroupKind{Group: testGroup, Kind: testCase.Kind}
mapping, err := mapper.RESTMapping(gk, preferredVersions...)
hasErr := err != nil
if hasErr != testCase.Err {
t.Errorf("%d: unexpected error behavior %t: %v", i, testCase.Err, err)
}
if hasErr {
continue
}
if mapping.Resource != testCase.Resource {
t.Errorf("%d: unexpected resource: %#v", i, mapping)
}
if mapping.MetadataAccessor == nil || mapping.ObjectConvertor == nil {
t.Errorf("%d: missing codec and accessor: %#v", i, mapping)
}
groupVersion := testCase.ExpectedGroupVersion
if groupVersion == nil {
groupVersion = &testCase.APIGroupVersions[0]
}
if mapping.GroupVersionKind.GroupVersion() != *groupVersion {
t.Errorf("%d: unexpected version: %#v", i, mapping)
}
}
}
func TestRESTMapperRESTMappingSelectsVersion(t *testing.T) {
expectedGroupVersion1 := unversioned.GroupVersion{Group: "tgroup", Version: "test1"}
expectedGroupVersion2 := unversioned.GroupVersion{Group: "tgroup", Version: "test2"}
expectedGroupVersion3 := unversioned.GroupVersion{Group: "tgroup", Version: "test3"}
internalObjectGK := unversioned.GroupKind{Group: "tgroup", Kind: "InternalObject"}
otherObjectGK := unversioned.GroupKind{Group: "tgroup", Kind: "OtherObject"}
mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}, fakeInterfaces)
mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace)
mapper.Add(expectedGroupVersion2.WithKind("OtherObject"), RESTScopeNamespace)
// pick default matching object kind based on search order
mapping, err := mapper.RESTMapping(otherObjectGK)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if mapping.Resource != "otherobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 {
t.Errorf("unexpected mapping: %#v", mapping)
}
mapping, err = mapper.RESTMapping(internalObjectGK)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if mapping.Resource != "internalobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion1 {
t.Errorf("unexpected mapping: %#v", mapping)
}
// mismatch of version
mapping, err = mapper.RESTMapping(internalObjectGK, expectedGroupVersion2.Version)
if err == nil {
t.Errorf("unexpected non-error")
}
mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion1.Version)
if err == nil {
t.Errorf("unexpected non-error")
}
// not in the search versions
mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version)
if err == nil {
t.Errorf("unexpected non-error")
}
// explicit search order
mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version, expectedGroupVersion1.Version)
if err == nil {
t.Errorf("unexpected non-error")
}
mapping, err = mapper.RESTMapping(otherObjectGK, expectedGroupVersion3.Version, expectedGroupVersion2.Version)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if mapping.Resource != "otherobjects" || mapping.GroupVersionKind.GroupVersion() != expectedGroupVersion2 {
t.Errorf("unexpected mapping: %#v", mapping)
}
}
func TestRESTMapperReportsErrorOnBadVersion(t *testing.T) {
expectedGroupVersion1 := unversioned.GroupVersion{Group: "tgroup", Version: "test1"}
expectedGroupVersion2 := unversioned.GroupVersion{Group: "tgroup", Version: "test2"}
internalObjectGK := unversioned.GroupKind{Group: "tgroup", Kind: "InternalObject"}
mapper := NewDefaultRESTMapper([]unversioned.GroupVersion{expectedGroupVersion1, expectedGroupVersion2}, unmatchedVersionInterfaces)
mapper.Add(expectedGroupVersion1.WithKind("InternalObject"), RESTScopeNamespace)
_, err := mapper.RESTMapping(internalObjectGK, expectedGroupVersion1.Version)
if err == nil {
t.Errorf("unexpected non-error")
}
}

View file

@ -1,51 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api_test
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
)
var _ meta.Object = &api.ObjectMeta{}
// TestFillObjectMetaSystemFields validates that system populated fields are set on an object
func TestFillObjectMetaSystemFields(t *testing.T) {
ctx := api.NewDefaultContext()
resource := api.ObjectMeta{}
api.FillObjectMetaSystemFields(ctx, &resource)
if resource.CreationTimestamp.Time.IsZero() {
t.Errorf("resource.CreationTimestamp is zero")
} else if len(resource.UID) == 0 {
t.Errorf("resource.UID missing")
}
}
// TestHasObjectMetaSystemFieldValues validates that true is returned if and only if all fields are populated
func TestHasObjectMetaSystemFieldValues(t *testing.T) {
ctx := api.NewDefaultContext()
resource := api.ObjectMeta{}
if api.HasObjectMetaSystemFieldValues(&resource) {
t.Errorf("the resource does not have all fields yet populated, but incorrectly reports it does")
}
api.FillObjectMetaSystemFields(ctx, &resource)
if !api.HasObjectMetaSystemFieldValues(&resource) {
t.Errorf("the resource does have all fields populated, but incorrectly reports it does not")
}
}

View file

@ -23,6 +23,18 @@ import (
"k8s.io/kubernetes/pkg/util/intstr"
)
const (
// The annotation value is a string specifying the hostname to be used for the pod e.g 'my-webserver-1'
PodHostnameAnnotation = "pod.beta.kubernetes.io/hostname"
// The annotation value is a string specifying the subdomain e.g. "my-web-service"
// If specified, on the the pod itself, "<hostname>.my-web-service.<namespace>.svc.<cluster domain>" would resolve to
// the pod's IP.
// If there is a headless service named "my-web-service" in the same namespace as the pod, then,
// <hostname>.my-web-service.<namespace>.svc.<cluster domain>" would be resolved by the cluster DNS Server.
PodSubdomainAnnotation = "pod.beta.kubernetes.io/subdomain"
)
// FindPort locates the container port for the given pod and portName. If the
// targetPort is a number, use that. If the targetPort is a string, look that
// string up in all named ports in all containers in the target pod. If no

View file

@ -1,110 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package pod
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/util/intstr"
)
func TestFindPort(t *testing.T) {
testCases := []struct {
name string
containers []api.Container
port intstr.IntOrString
expected int
pass bool
}{{
name: "valid int, no ports",
containers: []api.Container{{}},
port: intstr.FromInt(93),
expected: 93,
pass: true,
}, {
name: "valid int, with ports",
containers: []api.Container{{Ports: []api.ContainerPort{{
Name: "",
ContainerPort: 11,
Protocol: "TCP",
}, {
Name: "p",
ContainerPort: 22,
Protocol: "TCP",
}}}},
port: intstr.FromInt(93),
expected: 93,
pass: true,
}, {
name: "valid str, no ports",
containers: []api.Container{{}},
port: intstr.FromString("p"),
expected: 0,
pass: false,
}, {
name: "valid str, one ctr with ports",
containers: []api.Container{{Ports: []api.ContainerPort{{
Name: "",
ContainerPort: 11,
Protocol: "UDP",
}, {
Name: "p",
ContainerPort: 22,
Protocol: "TCP",
}, {
Name: "q",
ContainerPort: 33,
Protocol: "TCP",
}}}},
port: intstr.FromString("q"),
expected: 33,
pass: true,
}, {
name: "valid str, two ctr with ports",
containers: []api.Container{{}, {Ports: []api.ContainerPort{{
Name: "",
ContainerPort: 11,
Protocol: "UDP",
}, {
Name: "p",
ContainerPort: 22,
Protocol: "TCP",
}, {
Name: "q",
ContainerPort: 33,
Protocol: "TCP",
}}}},
port: intstr.FromString("q"),
expected: 33,
pass: true,
}}
for _, tc := range testCases {
port, err := FindPort(&api.Pod{Spec: api.PodSpec{Containers: tc.containers}},
&api.ServicePort{Protocol: "TCP", TargetPort: tc.port})
if err != nil && tc.pass {
t.Errorf("unexpected error for %s: %v", tc.name, err)
}
if err == nil && !tc.pass {
t.Errorf("unexpected non-error for %s: %d", tc.name, port)
}
if port != tc.expected {
t.Errorf("wrong result for %s: expected %d, got %d", tc.name, tc.expected, port)
}
}
}

View file

@ -1,128 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api
import (
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
)
type FakeAPIObject struct{}
func (obj *FakeAPIObject) GetObjectKind() unversioned.ObjectKind { return unversioned.EmptyObjectKind }
type ExtensionAPIObject struct {
unversioned.TypeMeta
ObjectMeta
}
func (obj *ExtensionAPIObject) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func TestGetReference(t *testing.T) {
table := map[string]struct {
obj runtime.Object
ref *ObjectReference
fieldPath string
shouldErr bool
}{
"pod": {
obj: &Pod{
ObjectMeta: ObjectMeta{
Name: "foo",
UID: "bar",
ResourceVersion: "42",
SelfLink: "/api/version1/pods/foo",
},
},
fieldPath: ".desiredState.containers[0]",
ref: &ObjectReference{
Kind: "Pod",
APIVersion: "version1",
Name: "foo",
UID: "bar",
ResourceVersion: "42",
FieldPath: ".desiredState.containers[0]",
},
},
"serviceList": {
obj: &ServiceList{
ListMeta: unversioned.ListMeta{
ResourceVersion: "42",
SelfLink: "/api/version2/services",
},
},
ref: &ObjectReference{
Kind: "ServiceList",
APIVersion: "version2",
ResourceVersion: "42",
},
},
"extensionAPIObject": {
obj: &ExtensionAPIObject{
TypeMeta: unversioned.TypeMeta{
Kind: "ExtensionAPIObject",
},
ObjectMeta: ObjectMeta{
Name: "foo",
UID: "bar",
ResourceVersion: "42",
SelfLink: "/custom_prefix/version1/extensions/foo",
},
},
ref: &ObjectReference{
Kind: "ExtensionAPIObject",
APIVersion: "version1",
Name: "foo",
UID: "bar",
ResourceVersion: "42",
},
},
"badSelfLink": {
obj: &ServiceList{
ListMeta: unversioned.ListMeta{
ResourceVersion: "42",
SelfLink: "version2/services",
},
},
shouldErr: true,
},
"error": {
obj: &FakeAPIObject{},
ref: nil,
shouldErr: true,
},
"errorNil": {
obj: nil,
ref: nil,
shouldErr: true,
},
}
for name, item := range table {
ref, err := GetPartialReference(item.obj, item.fieldPath)
if e, a := item.shouldErr, (err != nil); e != a {
t.Errorf("%v: expected %v, got %v, err %v", name, e, a, err)
continue
}
if e, a := item.ref, ref; !reflect.DeepEqual(e, a) {
t.Errorf("%v: expected %#v, got %#v", name, e, a)
}
}
}

View file

@ -1,59 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resource_test
import (
"fmt"
"k8s.io/kubernetes/pkg/api/resource"
)
func ExampleFormat() {
memorySize := resource.NewQuantity(5*1024*1024*1024, resource.BinarySI)
fmt.Printf("memorySize = %v\n", memorySize)
diskSize := resource.NewQuantity(5*1000*1000*1000, resource.DecimalSI)
fmt.Printf("diskSize = %v\n", diskSize)
cores := resource.NewMilliQuantity(5300, resource.DecimalSI)
fmt.Printf("cores = %v\n", cores)
// Output:
// memorySize = 5Gi
// diskSize = 5G
// cores = 5300m
}
func ExampleMustParse() {
memorySize := resource.MustParse("5Gi")
fmt.Printf("memorySize = %v (%v)\n", memorySize.Value(), memorySize.Format)
diskSize := resource.MustParse("5G")
fmt.Printf("diskSize = %v (%v)\n", diskSize.Value(), diskSize.Format)
cores := resource.MustParse("5300m")
fmt.Printf("milliCores = %v (%v)\n", cores.MilliValue(), cores.Format)
cores2 := resource.MustParse("5.4")
fmt.Printf("milliCores = %v (%v)\n", cores2.MilliValue(), cores2.Format)
// Output:
// memorySize = 5368709120 (BinarySI)
// diskSize = 5000000000 (DecimalSI)
// milliCores = 5300 (DecimalSI)
// milliCores = 5400 (DecimalSI)
}

View file

@ -1,810 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resource
import (
//"reflect"
"encoding/json"
"testing"
fuzz "github.com/google/gofuzz"
"github.com/spf13/pflag"
"speter.net/go/exp/math/dec/inf"
)
var (
testQuantityFlag = QuantityFlag("quantityFlag", "1M", "dummy flag for testing the quantity flag mechanism")
)
func dec(i int64, exponent int) *inf.Dec {
// See the below test-- scale is the negative of an exponent.
return inf.NewDec(i, inf.Scale(-exponent))
}
func TestDec(t *testing.T) {
table := []struct {
got *inf.Dec
expect string
}{
{dec(1, 0), "1"},
{dec(1, 1), "10"},
{dec(5, 2), "500"},
{dec(8, 3), "8000"},
{dec(2, 0), "2"},
{dec(1, -1), "0.1"},
{dec(3, -2), "0.03"},
{dec(4, -3), "0.004"},
}
for _, item := range table {
if e, a := item.expect, item.got.String(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
}
// TestQuantityParseZero ensures that when a 0 quantity is passed, its string value is 0
func TestQuantityParseZero(t *testing.T) {
zero := MustParse("0")
if expected, actual := "0", zero.String(); expected != actual {
t.Errorf("Expected %v, actual %v", expected, actual)
}
}
// TestQuantityAddZeroPreservesSuffix verifies that a suffix is preserved
// independent of the order of operations when adding a zero and non-zero val
func TestQuantityAddZeroPreservesSuffix(t *testing.T) {
testValues := []string{"100m", "1Gi"}
zero := MustParse("0")
for _, testValue := range testValues {
value := MustParse(testValue)
v1 := *value.Copy()
// ensure non-zero + zero = non-zero (suffix preserved)
err := v1.Add(zero)
if err != nil {
t.Errorf("Unexpected error %v", err)
}
// ensure zero + non-zero = non-zero (suffix preserved)
v2 := *zero.Copy()
err = v2.Add(value)
if err != nil {
t.Errorf("Unexpected error %v", err)
}
// ensure we preserved the input value
if v1.String() != testValue {
t.Errorf("Expected %v, actual %v", testValue, v1.String())
}
if v2.String() != testValue {
t.Errorf("Expected %v, actual %v", testValue, v2.String())
}
}
}
// TestQuantitySubZeroPreservesSuffix verifies that a suffix is preserved
// independent of the order of operations when subtracting a zero and non-zero val
func TestQuantitySubZeroPreservesSuffix(t *testing.T) {
testValues := []string{"100m", "1Gi"}
zero := MustParse("0")
for _, testValue := range testValues {
value := MustParse(testValue)
v1 := *value.Copy()
// ensure non-zero - zero = non-zero (suffix preserved)
err := v1.Sub(zero)
if err != nil {
t.Errorf("Unexpected error %v", err)
}
// ensure we preserved the input value
if v1.String() != testValue {
t.Errorf("Expected %v, actual %v", testValue, v1.String())
}
// ensure zero - non-zero = -non-zero (suffix preserved)
v2 := *zero.Copy()
err = v2.Sub(value)
if err != nil {
t.Errorf("Unexpected error %v", err)
}
negVal := *value.Copy()
err = negVal.Neg(negVal)
if err != nil {
t.Errorf("Unexpected error %v", err)
}
if v2.String() != negVal.String() {
t.Errorf("Expected %v, actual %v", negVal.String(), v2.String())
}
}
}
// Verifies that you get 0 as canonical value if internal value is 0, and not 0<suffix>
func TestQuantityCanocicalizeZero(t *testing.T) {
val := MustParse("1000m")
x := val.Amount
y := dec(1, 0)
z := val.Amount.Sub(x, y)
zero := Quantity{z, DecimalSI}
if expected, actual := "0", zero.String(); expected != actual {
t.Errorf("Expected %v, actual %v", expected, actual)
}
}
func TestQuantityCmp(t *testing.T) {
table := []struct {
x string
y string
expect int
}{
{"0", "0", 0},
{"100m", "50m", 1},
{"50m", "100m", -1},
{"10000T", "100Gi", 1},
}
for _, testCase := range table {
q1 := MustParse(testCase.x)
q2 := MustParse(testCase.y)
if result := q1.Cmp(q2); result != testCase.expect {
t.Errorf("X: %v, Y: %v, Expected: %v, Actual: %v", testCase.x, testCase.y, testCase.expect, result)
}
}
nils := []struct {
x *inf.Dec
y *inf.Dec
expect int
}{
{dec(0, 0), dec(0, 0), 0},
{nil, dec(0, 0), 0},
{dec(0, 0), nil, 0},
{nil, nil, 0},
{nil, dec(10, 0), -1},
{nil, dec(-10, 0), 1},
{dec(10, 0), nil, 1},
{dec(-10, 0), nil, -1},
}
for _, nilCase := range nils {
q1 := Quantity{nilCase.x, DecimalSI}
q2 := Quantity{nilCase.y, DecimalSI}
if result := q1.Cmp(q2); result != nilCase.expect {
t.Errorf("X: %v, Y: %v, Expected: %v, Actual: %v", nilCase.x, nilCase.y, nilCase.expect, result)
}
}
}
func TestQuantityParse(t *testing.T) {
table := []struct {
input string
expect Quantity
}{
{"0", Quantity{dec(0, 0), DecimalSI}},
{"0n", Quantity{dec(0, 0), DecimalSI}},
{"0u", Quantity{dec(0, 0), DecimalSI}},
{"0m", Quantity{dec(0, 0), DecimalSI}},
{"0Ki", Quantity{dec(0, 0), BinarySI}},
{"0k", Quantity{dec(0, 0), DecimalSI}},
{"0Mi", Quantity{dec(0, 0), BinarySI}},
{"0M", Quantity{dec(0, 0), DecimalSI}},
{"0Gi", Quantity{dec(0, 0), BinarySI}},
{"0G", Quantity{dec(0, 0), DecimalSI}},
{"0Ti", Quantity{dec(0, 0), BinarySI}},
{"0T", Quantity{dec(0, 0), DecimalSI}},
// Binary suffixes
{"1Ki", Quantity{dec(1024, 0), BinarySI}},
{"8Ki", Quantity{dec(8*1024, 0), BinarySI}},
{"7Mi", Quantity{dec(7*1024*1024, 0), BinarySI}},
{"6Gi", Quantity{dec(6*1024*1024*1024, 0), BinarySI}},
{"5Ti", Quantity{dec(5*1024*1024*1024*1024, 0), BinarySI}},
{"4Pi", Quantity{dec(4*1024*1024*1024*1024*1024, 0), BinarySI}},
{"3Ei", Quantity{dec(3*1024*1024*1024*1024*1024*1024, 0), BinarySI}},
{"10Ti", Quantity{dec(10*1024*1024*1024*1024, 0), BinarySI}},
{"100Ti", Quantity{dec(100*1024*1024*1024*1024, 0), BinarySI}},
// Decimal suffixes
{"5n", Quantity{dec(5, -9), DecimalSI}},
{"4u", Quantity{dec(4, -6), DecimalSI}},
{"3m", Quantity{dec(3, -3), DecimalSI}},
{"9", Quantity{dec(9, 0), DecimalSI}},
{"8k", Quantity{dec(8, 3), DecimalSI}},
{"7M", Quantity{dec(7, 6), DecimalSI}},
{"6G", Quantity{dec(6, 9), DecimalSI}},
{"5T", Quantity{dec(5, 12), DecimalSI}},
{"40T", Quantity{dec(4, 13), DecimalSI}},
{"300T", Quantity{dec(3, 14), DecimalSI}},
{"2P", Quantity{dec(2, 15), DecimalSI}},
{"1E", Quantity{dec(1, 18), DecimalSI}},
// Decimal exponents
{"1E-3", Quantity{dec(1, -3), DecimalExponent}},
{"1e3", Quantity{dec(1, 3), DecimalExponent}},
{"1E6", Quantity{dec(1, 6), DecimalExponent}},
{"1e9", Quantity{dec(1, 9), DecimalExponent}},
{"1E12", Quantity{dec(1, 12), DecimalExponent}},
{"1e15", Quantity{dec(1, 15), DecimalExponent}},
{"1E18", Quantity{dec(1, 18), DecimalExponent}},
// Nonstandard but still parsable
{"1e14", Quantity{dec(1, 14), DecimalExponent}},
{"1e13", Quantity{dec(1, 13), DecimalExponent}},
{"1e3", Quantity{dec(1, 3), DecimalExponent}},
{"100.035k", Quantity{dec(100035, 0), DecimalSI}},
// Things that look like floating point
{"0.001", Quantity{dec(1, -3), DecimalSI}},
{"0.0005k", Quantity{dec(5, -1), DecimalSI}},
{"0.005", Quantity{dec(5, -3), DecimalSI}},
{"0.05", Quantity{dec(5, -2), DecimalSI}},
{"0.5", Quantity{dec(5, -1), DecimalSI}},
{"0.00050k", Quantity{dec(5, -1), DecimalSI}},
{"0.00500", Quantity{dec(5, -3), DecimalSI}},
{"0.05000", Quantity{dec(5, -2), DecimalSI}},
{"0.50000", Quantity{dec(5, -1), DecimalSI}},
{"0.5e0", Quantity{dec(5, -1), DecimalExponent}},
{"0.5e-1", Quantity{dec(5, -2), DecimalExponent}},
{"0.5e-2", Quantity{dec(5, -3), DecimalExponent}},
{"0.5e0", Quantity{dec(5, -1), DecimalExponent}},
{"10.035M", Quantity{dec(10035, 3), DecimalSI}},
{"1.2e3", Quantity{dec(12, 2), DecimalExponent}},
{"1.3E+6", Quantity{dec(13, 5), DecimalExponent}},
{"1.40e9", Quantity{dec(14, 8), DecimalExponent}},
{"1.53E12", Quantity{dec(153, 10), DecimalExponent}},
{"1.6e15", Quantity{dec(16, 14), DecimalExponent}},
{"1.7E18", Quantity{dec(17, 17), DecimalExponent}},
{"9.01", Quantity{dec(901, -2), DecimalSI}},
{"8.1k", Quantity{dec(81, 2), DecimalSI}},
{"7.123456M", Quantity{dec(7123456, 0), DecimalSI}},
{"6.987654321G", Quantity{dec(6987654321, 0), DecimalSI}},
{"5.444T", Quantity{dec(5444, 9), DecimalSI}},
{"40.1T", Quantity{dec(401, 11), DecimalSI}},
{"300.2T", Quantity{dec(3002, 11), DecimalSI}},
{"2.5P", Quantity{dec(25, 14), DecimalSI}},
{"1.01E", Quantity{dec(101, 16), DecimalSI}},
// Things that saturate/round
{"3.001n", Quantity{dec(4, -9), DecimalSI}},
{"1.1E-9", Quantity{dec(2, -9), DecimalExponent}},
{"0.0000000001", Quantity{dec(1, -9), DecimalSI}},
{"0.0000000005", Quantity{dec(1, -9), DecimalSI}},
{"0.00000000050", Quantity{dec(1, -9), DecimalSI}},
{"0.5e-9", Quantity{dec(1, -9), DecimalExponent}},
{"0.9n", Quantity{dec(1, -9), DecimalSI}},
{"0.00000012345", Quantity{dec(124, -9), DecimalSI}},
{"0.00000012354", Quantity{dec(124, -9), DecimalSI}},
{"9Ei", Quantity{maxAllowed, BinarySI}},
{"9223372036854775807Ki", Quantity{maxAllowed, BinarySI}},
{"12E", Quantity{maxAllowed, DecimalSI}},
// We'll accept fractional binary stuff, too.
{"100.035Ki", Quantity{dec(10243584, -2), BinarySI}},
{"0.5Mi", Quantity{dec(.5*1024*1024, 0), BinarySI}},
{"0.05Gi", Quantity{dec(536870912, -1), BinarySI}},
{"0.025Ti", Quantity{dec(274877906944, -1), BinarySI}},
// Things written by trolls
{"0.000000000001Ki", Quantity{dec(2, -9), DecimalSI}}, // rounds up, changes format
{".001", Quantity{dec(1, -3), DecimalSI}},
{".0001k", Quantity{dec(100, -3), DecimalSI}},
{"1.", Quantity{dec(1, 0), DecimalSI}},
{"1.G", Quantity{dec(1, 9), DecimalSI}},
}
for _, item := range table {
got, err := ParseQuantity(item.input)
if err != nil {
t.Errorf("%v: unexpected error: %v", item.input, err)
continue
}
if e, a := item.expect.Amount, got.Amount; e.Cmp(a) != 0 {
t.Errorf("%v: expected %v, got %v", item.input, e, a)
}
if e, a := item.expect.Format, got.Format; e != a {
t.Errorf("%v: expected %#v, got %#v", item.input, e, a)
}
}
// Try the negative version of everything
desired := &inf.Dec{}
for _, item := range table {
got, err := ParseQuantity("-" + item.input)
if err != nil {
t.Errorf("-%v: unexpected error: %v", item.input, err)
continue
}
desired.Neg(item.expect.Amount)
if e, a := desired, got.Amount; e.Cmp(a) != 0 {
t.Errorf("%v: expected %v, got %v", item.input, e, a)
}
if e, a := item.expect.Format, got.Format; e != a {
t.Errorf("%v: expected %#v, got %#v", item.input, e, a)
}
}
// Try everything with an explicit +
for _, item := range table {
got, err := ParseQuantity("+" + item.input)
if err != nil {
t.Errorf("-%v: unexpected error: %v", item.input, err)
continue
}
if e, a := item.expect.Amount, got.Amount; e.Cmp(a) != 0 {
t.Errorf("%v: expected %v, got %v", item.input, e, a)
}
if e, a := item.expect.Format, got.Format; e != a {
t.Errorf("%v: expected %#v, got %#v", item.input, e, a)
}
}
invalid := []string{
"1.1.M",
"1+1.0M",
"0.1mi",
"0.1am",
"aoeu",
".5i",
"1i",
"-3.01i",
}
for _, item := range invalid {
_, err := ParseQuantity(item)
if err == nil {
t.Errorf("%v parsed unexpectedly", item)
}
}
}
func TestQuantityString(t *testing.T) {
table := []struct {
in Quantity
expect string
}{
{Quantity{dec(1024*1024*1024, 0), BinarySI}, "1Gi"},
{Quantity{dec(300*1024*1024, 0), BinarySI}, "300Mi"},
{Quantity{dec(6*1024, 0), BinarySI}, "6Ki"},
{Quantity{dec(1001*1024*1024*1024, 0), BinarySI}, "1001Gi"},
{Quantity{dec(1024*1024*1024*1024, 0), BinarySI}, "1Ti"},
{Quantity{dec(5, 0), BinarySI}, "5"},
{Quantity{dec(500, -3), BinarySI}, "500m"},
{Quantity{dec(1, 9), DecimalSI}, "1G"},
{Quantity{dec(1000, 6), DecimalSI}, "1G"},
{Quantity{dec(1000000, 3), DecimalSI}, "1G"},
{Quantity{dec(1000000000, 0), DecimalSI}, "1G"},
{Quantity{dec(1, -3), DecimalSI}, "1m"},
{Quantity{dec(80, -3), DecimalSI}, "80m"},
{Quantity{dec(1080, -3), DecimalSI}, "1080m"},
{Quantity{dec(108, -2), DecimalSI}, "1080m"},
{Quantity{dec(10800, -4), DecimalSI}, "1080m"},
{Quantity{dec(300, 6), DecimalSI}, "300M"},
{Quantity{dec(1, 12), DecimalSI}, "1T"},
{Quantity{dec(1234567, 6), DecimalSI}, "1234567M"},
{Quantity{dec(1234567, -3), BinarySI}, "1234567m"},
{Quantity{dec(3, 3), DecimalSI}, "3k"},
{Quantity{dec(1025, 0), BinarySI}, "1025"},
{Quantity{dec(0, 0), DecimalSI}, "0"},
{Quantity{dec(0, 0), BinarySI}, "0"},
{Quantity{dec(1, 9), DecimalExponent}, "1e9"},
{Quantity{dec(1, -3), DecimalExponent}, "1e-3"},
{Quantity{dec(1, -9), DecimalExponent}, "1e-9"},
{Quantity{dec(80, -3), DecimalExponent}, "80e-3"},
{Quantity{dec(300, 6), DecimalExponent}, "300e6"},
{Quantity{dec(1, 12), DecimalExponent}, "1e12"},
{Quantity{dec(1, 3), DecimalExponent}, "1e3"},
{Quantity{dec(3, 3), DecimalExponent}, "3e3"},
{Quantity{dec(3, 3), DecimalSI}, "3k"},
{Quantity{dec(0, 0), DecimalExponent}, "0"},
{Quantity{dec(1, -9), DecimalSI}, "1n"},
{Quantity{dec(80, -9), DecimalSI}, "80n"},
{Quantity{dec(1080, -9), DecimalSI}, "1080n"},
{Quantity{dec(108, -8), DecimalSI}, "1080n"},
{Quantity{dec(10800, -10), DecimalSI}, "1080n"},
{Quantity{dec(1, -6), DecimalSI}, "1u"},
{Quantity{dec(80, -6), DecimalSI}, "80u"},
{Quantity{dec(1080, -6), DecimalSI}, "1080u"},
}
for _, item := range table {
got := item.in.String()
if e, a := item.expect, got; e != a {
t.Errorf("%#v: expected %v, got %v", item.in, e, a)
}
}
desired := &inf.Dec{} // Avoid modifying the values in the table.
for _, item := range table {
if item.in.Amount.Cmp(decZero) == 0 {
// Don't expect it to print "-0" ever
continue
}
q := item.in
q.Amount = desired.Neg(q.Amount)
if e, a := "-"+item.expect, q.String(); e != a {
t.Errorf("%#v: expected %v, got %v", item.in, e, a)
}
}
}
func TestQuantityParseEmit(t *testing.T) {
table := []struct {
in string
expect string
}{
{"1Ki", "1Ki"},
{"1Mi", "1Mi"},
{"1Gi", "1Gi"},
{"1024Mi", "1Gi"},
{"1000M", "1G"},
{".001Ki", "1024m"},
{".000001Ki", "1024u"},
{".000000001Ki", "1024n"},
{".000000000001Ki", "2n"},
}
for _, item := range table {
q, err := ParseQuantity(item.in)
if err != nil {
t.Errorf("Couldn't parse %v", item.in)
continue
}
if e, a := item.expect, q.String(); e != a {
t.Errorf("%#v: expected %v, got %v", item.in, e, a)
}
}
for _, item := range table {
q, err := ParseQuantity("-" + item.in)
if err != nil {
t.Errorf("Couldn't parse %v", item.in)
continue
}
if q.Amount.Cmp(decZero) == 0 {
continue
}
if e, a := "-"+item.expect, q.String(); e != a {
t.Errorf("%#v: expected %v, got %v", item.in, e, a)
}
}
}
var fuzzer = fuzz.New().Funcs(
func(q *Quantity, c fuzz.Continue) {
q.Amount = &inf.Dec{}
if c.RandBool() {
q.Format = BinarySI
if c.RandBool() {
q.Amount.SetScale(0)
q.Amount.SetUnscaled(c.Int63())
return
}
// Be sure to test cases like 1Mi
q.Amount.SetScale(0)
q.Amount.SetUnscaled(c.Int63n(1024) << uint(10*c.Intn(5)))
return
}
if c.RandBool() {
q.Format = DecimalSI
} else {
q.Format = DecimalExponent
}
if c.RandBool() {
q.Amount.SetScale(inf.Scale(c.Intn(4)))
q.Amount.SetUnscaled(c.Int63())
return
}
// Be sure to test cases like 1M
q.Amount.SetScale(inf.Scale(3 - c.Intn(15)))
q.Amount.SetUnscaled(c.Int63n(1000))
},
)
func TestJSON(t *testing.T) {
for i := 0; i < 500; i++ {
q := &Quantity{}
fuzzer.Fuzz(q)
b, err := json.Marshal(q)
if err != nil {
t.Errorf("error encoding %v", q)
}
q2 := &Quantity{}
err = json.Unmarshal(b, q2)
if err != nil {
t.Errorf("%v: error decoding %v", q, string(b))
}
if q2.Amount.Cmp(q.Amount) != 0 {
t.Errorf("Expected equal: %v, %v (json was '%v')", q, q2, string(b))
}
}
}
func TestMilliNewSet(t *testing.T) {
table := []struct {
value int64
format Format
expect string
exact bool
}{
{1, DecimalSI, "1m", true},
{1000, DecimalSI, "1", true},
{1234000, DecimalSI, "1234", true},
{1024, BinarySI, "1024m", false}, // Format changes
{1000000, "invalidFormatDefaultsToExponent", "1e3", true},
{1024 * 1024, BinarySI, "1048576m", false}, // Format changes
}
for _, item := range table {
q := NewMilliQuantity(item.value, item.format)
if e, a := item.expect, q.String(); e != a {
t.Errorf("Expected %v, got %v; %#v", e, a, q)
}
if !item.exact {
continue
}
q2, err := ParseQuantity(q.String())
if err != nil {
t.Errorf("Round trip failed on %v", q)
}
if e, a := item.value, q2.MilliValue(); e != a {
t.Errorf("Expected %v, got %v", e, a)
}
}
for _, item := range table {
q := NewQuantity(0, item.format)
q.SetMilli(item.value)
if e, a := item.expect, q.String(); e != a {
t.Errorf("Set: Expected %v, got %v; %#v", e, a, q)
}
}
}
func TestNewSet(t *testing.T) {
table := []struct {
value int64
format Format
expect string
}{
{1, DecimalSI, "1"},
{1000, DecimalSI, "1k"},
{1234000, DecimalSI, "1234k"},
{1024, BinarySI, "1Ki"},
{1000000, "invalidFormatDefaultsToExponent", "1e6"},
{1024 * 1024, BinarySI, "1Mi"},
}
for _, item := range table {
q := NewQuantity(item.value, item.format)
if e, a := item.expect, q.String(); e != a {
t.Errorf("Expected %v, got %v; %#v", e, a, q)
}
q2, err := ParseQuantity(q.String())
if err != nil {
t.Errorf("Round trip failed on %v", q)
}
if e, a := item.value, q2.Value(); e != a {
t.Errorf("Expected %v, got %v", e, a)
}
}
for _, item := range table {
q := NewQuantity(0, item.format)
q.Set(item.value)
if e, a := item.expect, q.String(); e != a {
t.Errorf("Set: Expected %v, got %v; %#v", e, a, q)
}
}
}
func TestNewScaledSet(t *testing.T) {
table := []struct {
value int64
scale Scale
expect string
}{
{1, Nano, "1n"},
{1000, Nano, "1u"},
{1, Micro, "1u"},
{1000, Micro, "1m"},
{1, Milli, "1m"},
{1000, Milli, "1"},
{1, 0, "1"},
{0, Nano, "0"},
{0, Micro, "0"},
{0, Milli, "0"},
{0, 0, "0"},
}
for _, item := range table {
q := NewScaledQuantity(item.value, item.scale)
if e, a := item.expect, q.String(); e != a {
t.Errorf("Expected %v, got %v; %#v", e, a, q)
}
q2, err := ParseQuantity(q.String())
if err != nil {
t.Errorf("Round trip failed on %v", q)
}
if e, a := item.value, q2.ScaledValue(item.scale); e != a {
t.Errorf("Expected %v, got %v", e, a)
}
q3 := NewQuantity(0, DecimalSI)
q3.SetScaled(item.value, item.scale)
if q.Cmp(*q3) != 0 {
t.Errorf("Expected %v and %v to be equal", q, q3)
}
}
}
func TestScaledValue(t *testing.T) {
table := []struct {
fromScale Scale
toScale Scale
expected int64
}{
{Nano, Nano, 1},
{Nano, Micro, 1},
{Nano, Milli, 1},
{Nano, 0, 1},
{Micro, Nano, 1000},
{Micro, Micro, 1},
{Micro, Milli, 1},
{Micro, 0, 1},
{Milli, Nano, 1000 * 1000},
{Milli, Micro, 1000},
{Milli, Milli, 1},
{Milli, 0, 1},
{0, Nano, 1000 * 1000 * 1000},
{0, Micro, 1000 * 1000},
{0, Milli, 1000},
{0, 0, 1},
}
for _, item := range table {
q := NewScaledQuantity(1, item.fromScale)
if e, a := item.expected, q.ScaledValue(item.toScale); e != a {
t.Errorf("%v to %v: Expected %v, got %v", item.fromScale, item.toScale, e, a)
}
}
}
func TestUninitializedNoCrash(t *testing.T) {
var q Quantity
q.Value()
q.MilliValue()
q.Copy()
_ = q.String()
q.MarshalJSON()
}
func TestCopy(t *testing.T) {
q := NewQuantity(5, DecimalSI)
c := q.Copy()
c.Set(6)
if q.Value() == 6 {
t.Errorf("Copy didn't")
}
}
func TestQFlagSet(t *testing.T) {
qf := qFlag{&Quantity{}}
qf.Set("1Ki")
if e, a := "1Ki", qf.String(); e != a {
t.Errorf("Unexpected result %v != %v", e, a)
}
}
func TestQFlagIsPFlag(t *testing.T) {
var pfv pflag.Value = qFlag{}
if e, a := "quantity", pfv.Type(); e != a {
t.Errorf("Unexpected result %v != %v", e, a)
}
}
func TestSub(t *testing.T) {
tests := []struct {
a Quantity
b Quantity
expected Quantity
}{
{Quantity{dec(10, 0), DecimalSI}, Quantity{dec(1, 1), DecimalSI}, Quantity{dec(0, 0), DecimalSI}},
{Quantity{dec(10, 0), DecimalSI}, Quantity{dec(1, 0), BinarySI}, Quantity{dec(9, 0), DecimalSI}},
{Quantity{dec(10, 0), BinarySI}, Quantity{dec(1, 0), DecimalSI}, Quantity{dec(9, 0), BinarySI}},
{Quantity{nil, DecimalSI}, Quantity{dec(50, 0), DecimalSI}, Quantity{dec(-50, 0), DecimalSI}},
{Quantity{dec(50, 0), DecimalSI}, Quantity{nil, DecimalSI}, Quantity{dec(50, 0), DecimalSI}},
{Quantity{nil, DecimalSI}, Quantity{nil, DecimalSI}, Quantity{dec(0, 0), DecimalSI}},
}
for i, test := range tests {
test.a.Sub(test.b)
if test.a.Cmp(test.expected) != 0 {
t.Errorf("[%d] Expected %q, got %q", i, test.expected.String(), test.a.String())
}
}
}
func TestNeg(t *testing.T) {
tests := []struct {
a Quantity
b Quantity
expected Quantity
}{
{
a: Quantity{dec(0, 0), DecimalSI},
b: Quantity{dec(10, 0), DecimalSI},
expected: Quantity{dec(-10, 0), DecimalSI},
},
{
a: Quantity{dec(0, 0), DecimalSI},
b: Quantity{dec(-10, 0), DecimalSI},
expected: Quantity{dec(10, 0), DecimalSI},
},
{
a: Quantity{dec(0, 0), DecimalSI},
b: Quantity{dec(10, 0), BinarySI},
expected: Quantity{dec(-10, 0), BinarySI},
},
{
a: Quantity{dec(0, 0), DecimalSI},
b: Quantity{dec(0, 0), BinarySI},
expected: Quantity{dec(0, 0), BinarySI},
},
{
a: Quantity{},
b: Quantity{dec(10, 0), BinarySI},
expected: Quantity{dec(-10, 0), BinarySI},
},
{
a: Quantity{dec(10, 0), BinarySI},
b: Quantity{},
expected: Quantity{},
},
{
a: Quantity{dec(10, 0), BinarySI},
b: Quantity{Format: DecimalSI},
expected: Quantity{dec(0, 0), DecimalSI},
},
}
for i, test := range tests {
test.a.Neg(test.b)
// ensure value is same
if test.a.Cmp(test.expected) != 0 {
t.Errorf("[%d] Expected %q, got %q", i, test.expected.String(), test.a.String())
}
// ensure format is updated
if test.a.Format != test.expected.Format {
t.Errorf("[%d] Expected format %v, got format %v", i, test.expected.Format, test.a.Format)
}
}
}
func TestAdd(t *testing.T) {
tests := []struct {
a Quantity
b Quantity
expected Quantity
}{
{Quantity{dec(10, 0), DecimalSI}, Quantity{dec(1, 1), DecimalSI}, Quantity{dec(20, 0), DecimalSI}},
{Quantity{dec(10, 0), DecimalSI}, Quantity{dec(1, 0), BinarySI}, Quantity{dec(11, 0), DecimalSI}},
{Quantity{dec(10, 0), BinarySI}, Quantity{dec(1, 0), DecimalSI}, Quantity{dec(11, 0), BinarySI}},
{Quantity{nil, DecimalSI}, Quantity{dec(50, 0), DecimalSI}, Quantity{dec(50, 0), DecimalSI}},
{Quantity{dec(50, 0), DecimalSI}, Quantity{nil, DecimalSI}, Quantity{dec(50, 0), DecimalSI}},
{Quantity{nil, DecimalSI}, Quantity{nil, DecimalSI}, Quantity{dec(0, 0), DecimalSI}},
}
for i, test := range tests {
test.a.Add(test.b)
if test.a.Cmp(test.expected) != 0 {
t.Errorf("[%d] Expected %q, got %q", i, test.expected.String(), test.a.String())
}
}
}

View file

@ -1,85 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resource
import (
"math"
"math/big"
"testing"
)
func TestScaledValueInternal(t *testing.T) {
tests := []struct {
unscaled *big.Int
scale int
newScale int
want int64
}{
// remain scale
{big.NewInt(1000), 0, 0, 1000},
// scale down
{big.NewInt(1000), 0, -3, 1},
{big.NewInt(1000), 3, 0, 1},
{big.NewInt(0), 3, 0, 0},
// always round up
{big.NewInt(999), 3, 0, 1},
{big.NewInt(500), 3, 0, 1},
{big.NewInt(499), 3, 0, 1},
{big.NewInt(1), 3, 0, 1},
// large scaled value does not lose precision
{big.NewInt(0).Sub(maxInt64, bigOne), 1, 0, (math.MaxInt64-1)/10 + 1},
// large intermidiate result.
{big.NewInt(1).Exp(big.NewInt(10), big.NewInt(100), nil), 100, 0, 1},
// scale up
{big.NewInt(0), 0, 3, 0},
{big.NewInt(1), 0, 3, 1000},
{big.NewInt(1), -3, 0, 1000},
{big.NewInt(1000), -3, 2, 100000000},
{big.NewInt(0).Div(big.NewInt(math.MaxInt64), bigThousand), 0, 3,
(math.MaxInt64 / 1000) * 1000},
}
for i, tt := range tests {
old := (&big.Int{}).Set(tt.unscaled)
got := scaledValue(tt.unscaled, tt.scale, tt.newScale)
if got != tt.want {
t.Errorf("#%d: got = %v, want %v", i, got, tt.want)
}
if tt.unscaled.Cmp(old) != 0 {
t.Errorf("#%d: unscaled = %v, want %v", i, tt.unscaled, old)
}
}
}
func BenchmarkScaledValueSmall(b *testing.B) {
s := big.NewInt(1000)
for i := 0; i < b.N; i++ {
scaledValue(s, 3, 0)
}
}
func BenchmarkScaledValueLarge(b *testing.B) {
s := big.NewInt(math.MaxInt64)
s.Mul(s, big.NewInt(1000))
for i := 0; i < b.N; i++ {
scaledValue(s, 10, 0)
}
}

View file

@ -1,63 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api
import (
"testing"
"k8s.io/kubernetes/pkg/api/resource"
)
func TestResourceHelpers(t *testing.T) {
cpuLimit := resource.MustParse("10")
memoryLimit := resource.MustParse("10G")
resourceSpec := ResourceRequirements{
Limits: ResourceList{
"cpu": cpuLimit,
"memory": memoryLimit,
"kube.io/storage": memoryLimit,
},
}
if res := resourceSpec.Limits.Cpu(); *res != cpuLimit {
t.Errorf("expected cpulimit %v, got %v", cpuLimit, res)
}
if res := resourceSpec.Limits.Memory(); *res != memoryLimit {
t.Errorf("expected memorylimit %v, got %v", memoryLimit, res)
}
resourceSpec = ResourceRequirements{
Limits: ResourceList{
"memory": memoryLimit,
"kube.io/storage": memoryLimit,
},
}
if res := resourceSpec.Limits.Cpu(); res.Value() != 0 {
t.Errorf("expected cpulimit %v, got %v", 0, res)
}
if res := resourceSpec.Limits.Memory(); *res != memoryLimit {
t.Errorf("expected memorylimit %v, got %v", memoryLimit, res)
}
}
func TestDefaultResourceHelpers(t *testing.T) {
resourceList := ResourceList{}
if resourceList.Cpu().Format != resource.DecimalSI {
t.Errorf("expected %v, actual %v", resource.DecimalSI, resourceList.Cpu().Format)
}
if resourceList.Memory().Format != resource.BinarySI {
t.Errorf("expected %v, actual %v", resource.BinarySI, resourceList.Memory().Format)
}
}

View file

@ -1,126 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rest
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/validation/field"
)
// RESTCreateStrategy defines the minimum validation, accepted input, and
// name generation behavior to create an object that follows Kubernetes
// API conventions.
type RESTCreateStrategy interface {
runtime.ObjectTyper
// The name generate is used when the standard GenerateName field is set.
// The NameGenerator will be invoked prior to validation.
api.NameGenerator
// NamespaceScoped returns true if the object must be within a namespace.
NamespaceScoped() bool
// PrepareForCreate is invoked on create before validation to normalize
// the object. For example: remove fields that are not to be persisted,
// sort order-insensitive list fields, etc. This should not remove fields
// whose presence would be considered a validation error.
PrepareForCreate(obj runtime.Object)
// Validate is invoked after default fields in the object have been filled in before
// the object is persisted. This method should not mutate the object.
Validate(ctx api.Context, obj runtime.Object) field.ErrorList
// Canonicalize is invoked after validation has succeeded but before the
// object has been persisted. This method may mutate the object.
Canonicalize(obj runtime.Object)
}
// BeforeCreate ensures that common operations for all resources are performed on creation. It only returns
// errors that can be converted to api.Status. It invokes PrepareForCreate, then GenerateName, then Validate.
// It returns nil if the object should be created.
func BeforeCreate(strategy RESTCreateStrategy, ctx api.Context, obj runtime.Object) error {
objectMeta, kind, kerr := objectMetaAndKind(strategy, obj)
if kerr != nil {
return kerr
}
if strategy.NamespaceScoped() {
if !api.ValidNamespace(ctx, objectMeta) {
return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request")
}
} else {
objectMeta.Namespace = api.NamespaceNone
}
objectMeta.DeletionTimestamp = nil
objectMeta.DeletionGracePeriodSeconds = nil
strategy.PrepareForCreate(obj)
api.FillObjectMetaSystemFields(ctx, objectMeta)
api.GenerateName(strategy, objectMeta)
if errs := strategy.Validate(ctx, obj); len(errs) > 0 {
return errors.NewInvalid(kind.GroupKind(), objectMeta.Name, errs)
}
// Custom validation (including name validation) passed
// Now run common validation on object meta
// Do this *after* custom validation so that specific error messages are shown whenever possible
if errs := validation.ValidateObjectMeta(objectMeta, strategy.NamespaceScoped(), validation.ValidatePathSegmentName, field.NewPath("metadata")); len(errs) > 0 {
return errors.NewInvalid(kind.GroupKind(), objectMeta.Name, errs)
}
strategy.Canonicalize(obj)
return nil
}
// CheckGeneratedNameError checks whether an error that occurred creating a resource is due
// to generation being unable to pick a valid name.
func CheckGeneratedNameError(strategy RESTCreateStrategy, err error, obj runtime.Object) error {
if !errors.IsAlreadyExists(err) {
return err
}
objectMeta, kind, kerr := objectMetaAndKind(strategy, obj)
if kerr != nil {
return kerr
}
if len(objectMeta.GenerateName) == 0 {
return err
}
return errors.NewServerTimeoutForKind(kind.GroupKind(), "POST", 0)
}
// objectMetaAndKind retrieves kind and ObjectMeta from a runtime object, or returns an error.
func objectMetaAndKind(typer runtime.ObjectTyper, obj runtime.Object) (*api.ObjectMeta, unversioned.GroupVersionKind, error) {
objectMeta, err := api.ObjectMetaFor(obj)
if err != nil {
return nil, unversioned.GroupVersionKind{}, errors.NewInternalError(err)
}
kind, err := typer.ObjectKind(obj)
if err != nil {
return nil, unversioned.GroupVersionKind{}, errors.NewInternalError(err)
}
return objectMeta, kind, nil
}
// NamespaceScopedStrategy has a method to tell if the object must be in a namespace.
type NamespaceScopedStrategy interface {
// NamespaceScoped returns if the object must be in a namespace.
NamespaceScoped() bool
}

View file

@ -1,83 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rest
import (
"time"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
)
// RESTDeleteStrategy defines deletion behavior on an object that follows Kubernetes
// API conventions.
type RESTDeleteStrategy interface {
runtime.ObjectTyper
// CheckGracefulDelete should return true if the object can be gracefully deleted and set
// any default values on the DeleteOptions.
CheckGracefulDelete(obj runtime.Object, options *api.DeleteOptions) bool
}
// BeforeDelete tests whether the object can be gracefully deleted. If graceful is set the object
// should be gracefully deleted, if gracefulPending is set the object has already been gracefully deleted
// (and the provided grace period is longer than the time to deletion), and an error is returned if the
// condition cannot be checked or the gracePeriodSeconds is invalid. The options argument may be updated with
// default values if graceful is true.
func BeforeDelete(strategy RESTDeleteStrategy, ctx api.Context, obj runtime.Object, options *api.DeleteOptions) (graceful, gracefulPending bool, err error) {
if strategy == nil {
return false, false, nil
}
objectMeta, _, kerr := objectMetaAndKind(strategy, obj)
if kerr != nil {
return false, false, kerr
}
// if the object is already being deleted
if objectMeta.DeletionTimestamp != nil {
// if we are already being deleted, we may only shorten the deletion grace period
// this means the object was gracefully deleted previously but deletionGracePeriodSeconds was not set,
// so we force deletion immediately
if objectMeta.DeletionGracePeriodSeconds == nil {
return false, false, nil
}
// only a shorter grace period may be provided by a user
if options.GracePeriodSeconds != nil {
period := int64(*options.GracePeriodSeconds)
if period > *objectMeta.DeletionGracePeriodSeconds {
return false, true, nil
}
now := unversioned.NewTime(unversioned.Now().Add(time.Second * time.Duration(*options.GracePeriodSeconds)))
objectMeta.DeletionTimestamp = &now
objectMeta.DeletionGracePeriodSeconds = &period
options.GracePeriodSeconds = &period
return true, false, nil
}
// graceful deletion is pending, do nothing
options.GracePeriodSeconds = objectMeta.DeletionGracePeriodSeconds
return false, true, nil
}
if !strategy.CheckGracefulDelete(obj, options) {
return false, false, nil
}
now := unversioned.NewTime(unversioned.Now().Add(time.Second * time.Duration(*options.GracePeriodSeconds)))
objectMeta.DeletionTimestamp = &now
objectMeta.DeletionGracePeriodSeconds = options.GracePeriodSeconds
return true, false, nil
}

View file

@ -1,18 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package rest defines common logic around changes to Kubernetes resources.
package rest

View file

@ -1,28 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rest
import (
"k8s.io/kubernetes/pkg/runtime"
)
// RESTExportStrategy is the interface that defines how to export a Kubernetes object
type RESTExportStrategy interface {
// Export strips fields that can not be set by the user. If 'exact' is false
// fields specific to the cluster are also stripped
Export(obj runtime.Object, exact bool) error
}

View file

@ -1,293 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rest
import (
"io"
"net/http"
"net/url"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/watch"
)
//TODO:
// Storage interfaces need to be separated into two groups; those that operate
// on collections and those that operate on individually named items.
// Collection interfaces:
// (Method: Current -> Proposed)
// GET: Lister -> CollectionGetter
// WATCH: Watcher -> CollectionWatcher
// CREATE: Creater -> CollectionCreater
// DELETE: (n/a) -> CollectionDeleter
// UPDATE: (n/a) -> CollectionUpdater
//
// Single item interfaces:
// (Method: Current -> Proposed)
// GET: Getter -> NamedGetter
// WATCH: (n/a) -> NamedWatcher
// CREATE: (n/a) -> NamedCreater
// DELETE: Deleter -> NamedDeleter
// UPDATE: Update -> NamedUpdater
// Storage is a generic interface for RESTful storage services.
// Resources which are exported to the RESTful API of apiserver need to implement this interface. It is expected
// that objects may implement any of the below interfaces.
type Storage interface {
// New returns an empty object that can be used with Create and Update after request data has been put into it.
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
New() runtime.Object
}
// KindProvider specifies a different kind for its API than for its internal storage. This is necessary for external
// objects that are not compiled into the api server. For such objects, there is no in-memory representation for
// the object, so they must be represented as generic objects (e.g. RawJSON), but when we present the object as part of
// API discovery we want to present the specific kind, not the generic internal representation.
type KindProvider interface {
Kind() string
}
// Lister is an object that can retrieve resources that match the provided field and label criteria.
type Lister interface {
// NewList returns an empty object that can be used with the List call.
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
NewList() runtime.Object
// List selects resources in the storage which match to the selector. 'options' can be nil.
List(ctx api.Context, options *api.ListOptions) (runtime.Object, error)
}
// Exporter is an object that knows how to strip a RESTful resource for export
type Exporter interface {
// Export an object. Fields that are not user specified (e.g. Status, ObjectMeta.ResourceVersion) are stripped out
// Returns the stripped object. If 'exact' is true, fields that are specific to the cluster (e.g. namespace) are
// retained, otherwise they are stripped also.
Export(ctx api.Context, name string, opts unversioned.ExportOptions) (runtime.Object, error)
}
// Getter is an object that can retrieve a named RESTful resource.
type Getter interface {
// Get finds a resource in the storage by name and returns it.
// Although it can return an arbitrary error value, IsNotFound(err) is true for the
// returned error value err when the specified resource is not found.
Get(ctx api.Context, name string) (runtime.Object, error)
}
// GetterWithOptions is an object that retrieve a named RESTful resource and takes
// additional options on the get request. It allows a caller to also receive the
// subpath of the GET request.
type GetterWithOptions interface {
// Get finds a resource in the storage by name and returns it.
// Although it can return an arbitrary error value, IsNotFound(err) is true for the
// returned error value err when the specified resource is not found.
// The options object passed to it is of the same type returned by the NewGetOptions
// method.
Get(ctx api.Context, name string, options runtime.Object) (runtime.Object, error)
// NewGetOptions returns an empty options object that will be used to pass
// options to the Get method. It may return a bool and a string, if true, the
// value of the request path below the object will be included as the named
// string in the serialization of the runtime object. E.g., returning "path"
// will convert the trailing request scheme value to "path" in the map[string][]string
// passed to the converter.
NewGetOptions() (runtime.Object, bool, string)
}
// Deleter is an object that can delete a named RESTful resource.
type Deleter interface {
// Delete finds a resource in the storage and deletes it.
// Although it can return an arbitrary error value, IsNotFound(err) is true for the
// returned error value err when the specified resource is not found.
// Delete *may* return the object that was deleted, or a status object indicating additional
// information about deletion.
Delete(ctx api.Context, name string) (runtime.Object, error)
}
// GracefulDeleter knows how to pass deletion options to allow delayed deletion of a
// RESTful object.
type GracefulDeleter interface {
// Delete finds a resource in the storage and deletes it.
// If options are provided, the resource will attempt to honor them or return an invalid
// request error.
// Although it can return an arbitrary error value, IsNotFound(err) is true for the
// returned error value err when the specified resource is not found.
// Delete *may* return the object that was deleted, or a status object indicating additional
// information about deletion.
Delete(ctx api.Context, name string, options *api.DeleteOptions) (runtime.Object, error)
}
// GracefulDeleteAdapter adapts the Deleter interface to GracefulDeleter
type GracefulDeleteAdapter struct {
Deleter
}
// Delete implements RESTGracefulDeleter in terms of Deleter
func (w GracefulDeleteAdapter) Delete(ctx api.Context, name string, options *api.DeleteOptions) (runtime.Object, error) {
return w.Deleter.Delete(ctx, name)
}
// CollectionDeleter is an object that can delete a collection
// of RESTful resources.
type CollectionDeleter interface {
// DeleteCollection selects all resources in the storage matching given 'listOptions'
// and deletes them. If 'options' are provided, the resource will attempt to honor
// them or return an invalid request error.
// DeleteCollection may not be atomic - i.e. it may delete some objects and still
// return an error after it. On success, returns a list of deleted objects.
DeleteCollection(ctx api.Context, options *api.DeleteOptions, listOptions *api.ListOptions) (runtime.Object, error)
}
// Creater is an object that can create an instance of a RESTful object.
type Creater interface {
// New returns an empty object that can be used with Create after request data has been put into it.
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
New() runtime.Object
// Create creates a new version of a resource.
Create(ctx api.Context, obj runtime.Object) (runtime.Object, error)
}
// NamedCreater is an object that can create an instance of a RESTful object using a name parameter.
type NamedCreater interface {
// New returns an empty object that can be used with Create after request data has been put into it.
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
New() runtime.Object
// Create creates a new version of a resource. It expects a name parameter from the path.
// This is needed for create operations on subresources which include the name of the parent
// resource in the path.
Create(ctx api.Context, name string, obj runtime.Object) (runtime.Object, error)
}
// Updater is an object that can update an instance of a RESTful object.
type Updater interface {
// New returns an empty object that can be used with Update after request data has been put into it.
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
New() runtime.Object
// Update finds a resource in the storage and updates it. Some implementations
// may allow updates creates the object - they should set the created boolean
// to true.
Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error)
}
// CreaterUpdater is a storage object that must support both create and update.
// Go prevents embedded interfaces that implement the same method.
type CreaterUpdater interface {
Creater
Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error)
}
// CreaterUpdater must satisfy the Updater interface.
var _ Updater = CreaterUpdater(nil)
// Patcher is a storage object that supports both get and update.
type Patcher interface {
Getter
Updater
}
// Watcher should be implemented by all Storage objects that
// want to offer the ability to watch for changes through the watch api.
type Watcher interface {
// 'label' selects on labels; 'field' selects on the object's fields. Not all fields
// are supported; an error should be returned if 'field' tries to select on a field that
// isn't supported. 'resourceVersion' allows for continuing/starting a watch at a
// particular version.
Watch(ctx api.Context, options *api.ListOptions) (watch.Interface, error)
}
// StandardStorage is an interface covering the common verbs. Provided for testing whether a
// resource satisfies the normal storage methods. Use Storage when passing opaque storage objects.
type StandardStorage interface {
Getter
Lister
CreaterUpdater
GracefulDeleter
CollectionDeleter
Watcher
}
// Redirector know how to return a remote resource's location.
type Redirector interface {
// ResourceLocation should return the remote location of the given resource, and an optional transport to use to request it, or an error.
ResourceLocation(ctx api.Context, id string) (remoteLocation *url.URL, transport http.RoundTripper, err error)
}
// Responder abstracts the normal response behavior for a REST method and is passed to callers that
// may wish to handle the response directly in some cases, but delegate to the normal error or object
// behavior in other cases.
type Responder interface {
// Object writes the provided object to the response. Invoking this method multiple times is undefined.
Object(statusCode int, obj runtime.Object)
// Error writes the provided error to the response. This method may only be invoked once.
Error(err error)
}
// Connecter is a storage object that responds to a connection request.
type Connecter interface {
// Connect returns an http.Handler that will handle the request/response for a given API invocation.
// The provided responder may be used for common API responses. The responder will write both status
// code and body, so the ServeHTTP method should exit after invoking the responder. The Handler will
// be used for a single API request and then discarded. The Responder is guaranteed to write to the
// same http.ResponseWriter passed to ServeHTTP.
Connect(ctx api.Context, id string, options runtime.Object, r Responder) (http.Handler, error)
// NewConnectOptions returns an empty options object that will be used to pass
// options to the Connect method. If nil, then a nil options object is passed to
// Connect. It may return a bool and a string. If true, the value of the request
// path below the object will be included as the named string in the serialization
// of the runtime object.
NewConnectOptions() (runtime.Object, bool, string)
// ConnectMethods returns the list of HTTP methods handled by Connect
ConnectMethods() []string
}
// ResourceStreamer is an interface implemented by objects that prefer to be streamed from the server
// instead of decoded directly.
type ResourceStreamer interface {
// InputStream should return an io.ReadCloser if the provided object supports streaming. The desired
// api version and a accept header (may be empty) are passed to the call. If no error occurs,
// the caller may return a flag indicating whether the result should be flushed as writes occur
// and a content type string that indicates the type of the stream.
// If a null stream is returned, a StatusNoContent response wil be generated.
InputStream(apiVersion, acceptHeader string) (stream io.ReadCloser, flush bool, mimeType string, err error)
}
// StorageMetadata is an optional interface that callers can implement to provide additional
// information about their Storage objects.
type StorageMetadata interface {
// ProducesMIMETypes returns a list of the MIME types the specified HTTP verb (GET, POST, DELETE,
// PATCH) can respond with.
ProducesMIMETypes(verb string) []string
}
// ConnectRequest is an object passed to admission control for Connect operations
type ConnectRequest struct {
// Name is the name of the object on which the connect request was made
Name string
// Options is the options object passed to the connect request. See the NewConnectOptions method on Connecter
Options runtime.Object
// ResourcePath is the path for the resource in the REST server (ie. "pods/proxy")
ResourcePath string
}
func (obj *ConnectRequest) GetObjectKind() unversioned.ObjectKind { return unversioned.EmptyObjectKind }

File diff suppressed because it is too large Load diff

View file

@ -1,42 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rest
import (
"k8s.io/kubernetes/pkg/runtime"
)
// ObjectFunc is a function to act on a given object. An error may be returned
// if the hook cannot be completed. An ObjectFunc may transform the provided
// object.
type ObjectFunc func(obj runtime.Object) error
// AllFuncs returns an ObjectFunc that attempts to run all of the provided functions
// in order, returning early if there are any errors.
func AllFuncs(fns ...ObjectFunc) ObjectFunc {
return func(obj runtime.Object) error {
for _, fn := range fns {
if fn == nil {
continue
}
if err := fn(obj); err != nil {
return err
}
}
return nil
}
}

View file

@ -1,105 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rest
import (
"fmt"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/validation/field"
)
// RESTUpdateStrategy defines the minimum validation, accepted input, and
// name generation behavior to update an object that follows Kubernetes
// API conventions. A resource may have many UpdateStrategies, depending on
// the call pattern in use.
type RESTUpdateStrategy interface {
runtime.ObjectTyper
// NamespaceScoped returns true if the object must be within a namespace.
NamespaceScoped() bool
// AllowCreateOnUpdate returns true if the object can be created by a PUT.
AllowCreateOnUpdate() bool
// PrepareForUpdate is invoked on update before validation to normalize
// the object. For example: remove fields that are not to be persisted,
// sort order-insensitive list fields, etc. This should not remove fields
// whose presence would be considered a validation error.
PrepareForUpdate(obj, old runtime.Object)
// ValidateUpdate is invoked after default fields in the object have been
// filled in before the object is persisted. This method should not mutate
// the object.
ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList
// Canonicalize is invoked after validation has succeeded but before the
// object has been persisted. This method may mutate the object.
Canonicalize(obj runtime.Object)
// AllowUnconditionalUpdate returns true if the object can be updated
// unconditionally (irrespective of the latest resource version), when
// there is no resource version specified in the object.
AllowUnconditionalUpdate() bool
}
// TODO: add other common fields that require global validation.
func validateCommonFields(obj, old runtime.Object) (field.ErrorList, error) {
allErrs := field.ErrorList{}
objectMeta, err := api.ObjectMetaFor(obj)
if err != nil {
return nil, fmt.Errorf("failed to get new object metadata: %v", err)
}
oldObjectMeta, err := api.ObjectMetaFor(old)
if err != nil {
return nil, fmt.Errorf("failed to get old object metadata: %v", err)
}
allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(objectMeta, oldObjectMeta, field.NewPath("metadata"))...)
return allErrs, nil
}
// BeforeUpdate ensures that common operations for all resources are performed on update. It only returns
// errors that can be converted to api.Status. It will invoke update validation with the provided existing
// and updated objects.
func BeforeUpdate(strategy RESTUpdateStrategy, ctx api.Context, obj, old runtime.Object) error {
objectMeta, kind, kerr := objectMetaAndKind(strategy, obj)
if kerr != nil {
return kerr
}
if strategy.NamespaceScoped() {
if !api.ValidNamespace(ctx, objectMeta) {
return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request")
}
} else {
objectMeta.Namespace = api.NamespaceNone
}
strategy.PrepareForUpdate(obj, old)
// Ensure some common fields, like UID, are validated for all resources.
errs, err := validateCommonFields(obj, old)
if err != nil {
return errors.NewInternalError(err)
}
errs = append(errs, strategy.ValidateUpdate(ctx, obj, old)...)
if len(errs) > 0 {
return errors.NewInvalid(kind.GroupKind(), objectMeta.Name, errs)
}
strategy.Canonicalize(obj)
return nil
}

View file

@ -1,95 +0,0 @@
// +build proto
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api_test
import (
"encoding/hex"
"math/rand"
"testing"
"github.com/gogo/protobuf/proto"
"k8s.io/kubernetes/pkg/api"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/v1"
_ "k8s.io/kubernetes/pkg/apis/extensions"
_ "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/runtime/protobuf"
"k8s.io/kubernetes/pkg/util"
)
func init() {
codecsToTest = append(codecsToTest, func(version string, item runtime.Object) (runtime.Codec, error) {
return protobuf.NewCodec(version, api.Scheme, api.Scheme, api.Scheme), nil
})
}
func TestProtobufRoundTrip(t *testing.T) {
obj := &v1.Pod{}
apitesting.FuzzerFor(t, "v1", rand.NewSource(benchmarkSeed)).Fuzz(obj)
data, err := obj.Marshal()
if err != nil {
t.Fatal(err)
}
out := &v1.Pod{}
if err := out.Unmarshal(data); err != nil {
t.Fatal(err)
}
if !api.Semantic.Equalities.DeepEqual(out, obj) {
t.Logf("marshal\n%s", hex.Dump(data))
t.Fatalf("Unmarshal is unequal\n%s", util.ObjectGoPrintSideBySide(out, obj))
}
}
func BenchmarkEncodeProtobufGeneratedMarshal(b *testing.B) {
items := benchmarkItems()
width := len(items)
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := items[i%width].Marshal(); err != nil {
b.Fatal(err)
}
}
b.StopTimer()
}
// BenchmarkDecodeJSON provides a baseline for regular JSON decode performance
func BenchmarkDecodeIntoProtobuf(b *testing.B) {
items := benchmarkItems()
width := len(items)
encoded := make([][]byte, width)
for i := range items {
data, err := (&items[i]).Marshal()
if err != nil {
b.Fatal(err)
}
encoded[i] = data
validate := &v1.Pod{}
if err := proto.Unmarshal(data, validate); err != nil {
b.Fatalf("Failed to unmarshal %d: %v\n%#v", i, err, items[i])
}
}
for i := 0; i < b.N; i++ {
obj := v1.Pod{}
if err := proto.Unmarshal(encoded[i%width], &obj); err != nil {
b.Fatal(err)
}
}
}

View file

@ -1,417 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api_test
import (
"encoding/json"
"math/rand"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
flag "github.com/spf13/pflag"
"github.com/ugorji/go/codec"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/sets"
)
var fuzzIters = flag.Int("fuzz-iters", 20, "How many fuzzing iterations to do.")
var codecsToTest = []func(version unversioned.GroupVersion, item runtime.Object) (runtime.Codec, error){
func(version unversioned.GroupVersion, item runtime.Object) (runtime.Codec, error) {
return testapi.GetCodecForObject(item)
},
}
func fuzzInternalObject(t *testing.T, forVersion unversioned.GroupVersion, item runtime.Object, seed int64) runtime.Object {
apitesting.FuzzerFor(t, forVersion, rand.NewSource(seed)).Fuzz(item)
j, err := meta.TypeAccessor(item)
if err != nil {
t.Fatalf("Unexpected error %v for %#v", err, item)
}
j.SetKind("")
j.SetAPIVersion("")
return item
}
func roundTrip(t *testing.T, codec runtime.Codec, item runtime.Object) {
//t.Logf("codec: %#v", codec)
printer := spew.ConfigState{DisableMethods: true}
name := reflect.TypeOf(item).Elem().Name()
data, err := runtime.Encode(codec, item)
if err != nil {
t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", item))
return
}
obj2, err := runtime.Decode(codec, data)
if err != nil {
t.Errorf("0: %v: %v\nCodec: %v\nData: %s\nSource: %#v", name, err, codec, string(data), printer.Sprintf("%#v", item))
return
}
if !api.Semantic.DeepEqual(item, obj2) {
t.Errorf("\n1: %v: diff: %v\nCodec: %v\nSource:\n\n%#v\n\nEncoded:\n\n%s\n\nFinal:\n\n%#v", name, util.ObjectGoPrintDiff(item, obj2), codec, printer.Sprintf("%#v", item), string(data), printer.Sprintf("%#v", obj2))
return
}
obj3 := reflect.New(reflect.TypeOf(item).Elem()).Interface().(runtime.Object)
if err := runtime.DecodeInto(codec, data, obj3); err != nil {
t.Errorf("2: %v: %v", name, err)
return
}
if !api.Semantic.DeepEqual(item, obj3) {
t.Errorf("3: %v: diff: %v\nCodec: %v", name, util.ObjectDiff(item, obj3), codec)
return
}
}
// roundTripSame verifies the same source object is tested in all API versions.
func roundTripSame(t *testing.T, group testapi.TestGroup, item runtime.Object, except ...string) {
set := sets.NewString(except...)
seed := rand.Int63()
fuzzInternalObject(t, group.InternalGroupVersion(), item, seed)
version := *group.GroupVersion()
codecs := []runtime.Codec{}
for _, fn := range codecsToTest {
codec, err := fn(version, item)
if err != nil {
t.Errorf("unable to get codec: %v", err)
return
}
codecs = append(codecs, codec)
}
if !set.Has(version.String()) {
fuzzInternalObject(t, version, item, seed)
for _, codec := range codecs {
roundTrip(t, codec, item)
}
}
}
// For debugging problems
func TestSpecificKind(t *testing.T) {
// api.Scheme.Log(t)
// defer api.Scheme.Log(nil)
kind := "DaemonSet"
for i := 0; i < *fuzzIters; i++ {
doRoundTripTest(testapi.Groups["extensions"], kind, t)
if t.Failed() {
break
}
}
}
func TestList(t *testing.T) {
// api.Scheme.Log(t)
// defer api.Scheme.Log(nil)
kind := "List"
item, err := api.Scheme.New(api.SchemeGroupVersion.WithKind(kind))
if err != nil {
t.Errorf("Couldn't make a %v? %v", kind, err)
return
}
roundTripSame(t, testapi.Default, item)
}
var nonRoundTrippableTypes = sets.NewString("ExportOptions")
var nonInternalRoundTrippableTypes = sets.NewString("List", "ListOptions", "ExportOptions")
var nonRoundTrippableTypesByVersion = map[string][]string{}
func TestRoundTripTypes(t *testing.T) {
// api.Scheme.Log(t)
// defer api.Scheme.Log(nil)
for groupKey, group := range testapi.Groups {
for kind := range api.Scheme.KnownTypes(group.InternalGroupVersion()) {
t.Logf("working on %v in %v", kind, groupKey)
if nonRoundTrippableTypes.Has(kind) {
continue
}
// Try a few times, since runTest uses random values.
for i := 0; i < *fuzzIters; i++ {
doRoundTripTest(group, kind, t)
if t.Failed() {
break
}
}
}
}
}
func doRoundTripTest(group testapi.TestGroup, kind string, t *testing.T) {
item, err := api.Scheme.New(group.InternalGroupVersion().WithKind(kind))
if err != nil {
t.Fatalf("Couldn't make a %v? %v", kind, err)
}
if _, err := meta.TypeAccessor(item); err != nil {
t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableTypes: %v", kind, err)
}
if api.Scheme.Recognizes(group.GroupVersion().WithKind(kind)) {
roundTripSame(t, group, item, nonRoundTrippableTypesByVersion[kind]...)
}
if !nonInternalRoundTrippableTypes.Has(kind) && api.Scheme.Recognizes(group.GroupVersion().WithKind(kind)) {
roundTrip(t, group.Codec(), fuzzInternalObject(t, group.InternalGroupVersion(), item, rand.Int63()))
}
}
func TestEncode_Ptr(t *testing.T) {
grace := int64(30)
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Labels: map[string]string{"name": "foo"},
},
Spec: api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
SecurityContext: &api.PodSecurityContext{},
},
}
obj := runtime.Object(pod)
data, err := runtime.Encode(testapi.Default.Codec(), obj)
obj2, err2 := runtime.Decode(testapi.Default.Codec(), data)
if err != nil || err2 != nil {
t.Fatalf("Failure: '%v' '%v'", err, err2)
}
if _, ok := obj2.(*api.Pod); !ok {
t.Fatalf("Got wrong type")
}
if !api.Semantic.DeepEqual(obj2, pod) {
t.Errorf("\nExpected:\n\n %#v,\n\nGot:\n\n %#vDiff: %v\n\n", pod, obj2, util.ObjectDiff(obj2, pod))
}
}
func TestBadJSONRejection(t *testing.T) {
badJSONMissingKind := []byte(`{ }`)
if _, err := runtime.Decode(testapi.Default.Codec(), badJSONMissingKind); err == nil {
t.Errorf("Did not reject despite lack of kind field: %s", badJSONMissingKind)
}
badJSONUnknownType := []byte(`{"kind": "bar"}`)
if _, err1 := runtime.Decode(testapi.Default.Codec(), badJSONUnknownType); err1 == nil {
t.Errorf("Did not reject despite use of unknown type: %s", badJSONUnknownType)
}
/*badJSONKindMismatch := []byte(`{"kind": "Pod"}`)
if err2 := DecodeInto(badJSONKindMismatch, &Minion{}); err2 == nil {
t.Errorf("Kind is set but doesn't match the object type: %s", badJSONKindMismatch)
}*/
}
func TestUnversionedTypes(t *testing.T) {
testcases := []runtime.Object{
&unversioned.Status{Status: "Failure", Message: "something went wrong"},
&unversioned.APIVersions{Versions: []string{"A", "B", "C"}},
&unversioned.APIGroupList{Groups: []unversioned.APIGroup{{Name: "mygroup"}}},
&unversioned.APIGroup{Name: "mygroup"},
&unversioned.APIResourceList{GroupVersion: "mygroup/myversion"},
}
for _, obj := range testcases {
// Make sure the unversioned codec can encode
unversionedJSON, err := runtime.Encode(testapi.Default.Codec(), obj)
if err != nil {
t.Errorf("%v: unexpected error: %v", obj, err)
continue
}
// Make sure the versioned codec under test can decode
versionDecodedObject, err := runtime.Decode(testapi.Default.Codec(), unversionedJSON)
if err != nil {
t.Errorf("%v: unexpected error: %v", obj, err)
continue
}
// Make sure it decodes correctly
if !reflect.DeepEqual(obj, versionDecodedObject) {
t.Errorf("%v: expected %#v, got %#v", obj, obj, versionDecodedObject)
continue
}
}
}
const benchmarkSeed = 100
func benchmarkItems() []v1.Pod {
apiObjectFuzzer := apitesting.FuzzerFor(nil, api.SchemeGroupVersion, rand.NewSource(benchmarkSeed))
items := make([]v1.Pod, 2)
for i := range items {
apiObjectFuzzer.Fuzz(&items[i])
}
return items
}
// BenchmarkEncodeCodec measures the cost of performing a codec encode, which includes
// reflection (to clear APIVersion and Kind)
func BenchmarkEncodeCodec(b *testing.B) {
items := benchmarkItems()
width := len(items)
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := runtime.Encode(testapi.Default.Codec(), &items[i%width]); err != nil {
b.Fatal(err)
}
}
b.StopTimer()
}
// BenchmarkEncodeJSONMarshal provides a baseline for regular JSON encode performance
func BenchmarkEncodeJSONMarshal(b *testing.B) {
items := benchmarkItems()
width := len(items)
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := json.Marshal(&items[i%width]); err != nil {
b.Fatal(err)
}
}
b.StopTimer()
}
func BenchmarkDecodeCodec(b *testing.B) {
codec := testapi.Default.Codec()
items := benchmarkItems()
width := len(items)
encoded := make([][]byte, width)
for i := range items {
data, err := runtime.Encode(codec, &items[i])
if err != nil {
b.Fatal(err)
}
encoded[i] = data
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := runtime.Decode(codec, encoded[i%width]); err != nil {
b.Fatal(err)
}
}
b.StopTimer()
}
func BenchmarkDecodeIntoExternalCodec(b *testing.B) {
codec := testapi.Default.Codec()
items := benchmarkItems()
width := len(items)
encoded := make([][]byte, width)
for i := range items {
data, err := runtime.Encode(codec, &items[i])
if err != nil {
b.Fatal(err)
}
encoded[i] = data
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
obj := v1.Pod{}
if err := runtime.DecodeInto(codec, encoded[i%width], &obj); err != nil {
b.Fatal(err)
}
}
b.StopTimer()
}
func BenchmarkDecodeIntoInternalCodec(b *testing.B) {
codec := testapi.Default.Codec()
items := benchmarkItems()
width := len(items)
encoded := make([][]byte, width)
for i := range items {
data, err := runtime.Encode(codec, &items[i])
if err != nil {
b.Fatal(err)
}
encoded[i] = data
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
obj := api.Pod{}
if err := runtime.DecodeInto(codec, encoded[i%width], &obj); err != nil {
b.Fatal(err)
}
}
b.StopTimer()
}
// BenchmarkDecodeJSON provides a baseline for regular JSON decode performance
func BenchmarkDecodeIntoJSON(b *testing.B) {
codec := testapi.Default.Codec()
items := benchmarkItems()
width := len(items)
encoded := make([][]byte, width)
for i := range items {
data, err := runtime.Encode(codec, &items[i])
if err != nil {
b.Fatal(err)
}
encoded[i] = data
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
obj := v1.Pod{}
if err := json.Unmarshal(encoded[i%width], &obj); err != nil {
b.Fatal(err)
}
}
b.StopTimer()
}
// BenchmarkDecodeJSON provides a baseline for codecgen JSON decode performance
func BenchmarkDecodeIntoJSONCodecGen(b *testing.B) {
kcodec := testapi.Default.Codec()
items := benchmarkItems()
width := len(items)
encoded := make([][]byte, width)
for i := range items {
data, err := runtime.Encode(kcodec, &items[i])
if err != nil {
b.Fatal(err)
}
encoded[i] = data
}
handler := &codec.JsonHandle{}
b.ResetTimer()
for i := 0; i < b.N; i++ {
obj := v1.Pod{}
if err := codec.NewDecoderBytes(encoded[i%width], handler).Decode(&obj); err != nil {
b.Fatal(err)
}
}
b.StopTimer()
}

View file

@ -1,5 +1,3 @@
// +build !linux,!darwin,!freebsd,!openbsd,!netbsd,!dragonfly
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
@ -16,9 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package flock
package service
// Acquire is not implemented on non-unix systems.
func Acquire(path string) error {
return nil
}
const (
// AnnotationLoadBalancerSourceRangesKey is the key of the annotation on a service to set allowed ingress ranges on their LoadBalancers
//
// It should be a comma-separated list of CIDRs, e.g. `0.0.0.0/0` to
// allow full access (the default) or `18.0.0.0/8,56.0.0.0/8` to allow
// access only from the CIDRs currently allocated to MIT & the USPS.
//
// Not all cloud providers support this annotation, though AWS & GCE do.
AnnotationLoadBalancerSourceRangesKey = "service.beta.kubernetes.io/load-balancer-source-ranges"
)

View file

@ -0,0 +1,54 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package service
import (
"fmt"
"strings"
netsets "k8s.io/kubernetes/pkg/util/net/sets"
)
const (
defaultLoadBalancerSourceRanges = "0.0.0.0/0"
)
// IsAllowAll checks whether the netsets.IPNet allows traffic from 0.0.0.0/0
func IsAllowAll(ipnets netsets.IPNet) bool {
for _, s := range ipnets.StringSlice() {
if s == "0.0.0.0/0" {
return true
}
}
return false
}
// GetLoadBalancerSourceRanges verifies and parses the AnnotationLoadBalancerSourceRangesKey annotation from a service,
// extracting the source ranges to allow, and if not present returns a default (allow-all) value.
func GetLoadBalancerSourceRanges(annotations map[string]string) (netsets.IPNet, error) {
val := annotations[AnnotationLoadBalancerSourceRangesKey]
val = strings.TrimSpace(val)
if val == "" {
val = defaultLoadBalancerSourceRanges
}
specs := strings.Split(val, ",")
ipnets, err := netsets.ParseIPNets(specs...)
if err != nil {
return nil, fmt.Errorf("Service annotation %s:%s is not valid. Expecting a comma-separated list of source IP ranges. For example, 10.0.0.0/24,192.168.2.0/24", AnnotationLoadBalancerSourceRangesKey, val)
}
return ipnets, nil
}

View file

@ -20,6 +20,7 @@ package testapi
import (
"fmt"
"os"
"reflect"
"strings"
"k8s.io/kubernetes/pkg/api"
@ -27,11 +28,13 @@ import (
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/runtime"
_ "k8s.io/kubernetes/pkg/api/install"
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
_ "k8s.io/kubernetes/pkg/apis/batch/install"
_ "k8s.io/kubernetes/pkg/apis/componentconfig/install"
_ "k8s.io/kubernetes/pkg/apis/extensions/install"
_ "k8s.io/kubernetes/pkg/apis/metrics/install"
@ -41,12 +44,14 @@ var (
Groups = make(map[string]TestGroup)
Default TestGroup
Autoscaling TestGroup
Batch TestGroup
Extensions TestGroup
)
type TestGroup struct {
externalGroupVersion unversioned.GroupVersion
internalGroupVersion unversioned.GroupVersion
internalTypes map[string]reflect.Type
}
func init() {
@ -59,9 +64,11 @@ func init() {
panic(fmt.Sprintf("Error parsing groupversion %v: %v", gvString, err))
}
internalGroupVersion := unversioned.GroupVersion{Group: groupVersion.Group, Version: runtime.APIVersionInternal}
Groups[groupVersion.Group] = TestGroup{
externalGroupVersion: groupVersion,
internalGroupVersion: unversioned.GroupVersion{Group: groupVersion.Group, Version: runtime.APIVersionInternal},
internalGroupVersion: internalGroupVersion,
internalTypes: api.Scheme.KnownTypes(internalGroupVersion),
}
}
}
@ -70,23 +77,55 @@ func init() {
Groups[api.GroupName] = TestGroup{
externalGroupVersion: unversioned.GroupVersion{Group: api.GroupName, Version: registered.GroupOrDie(api.GroupName).GroupVersion.Version},
internalGroupVersion: api.SchemeGroupVersion,
}
}
if _, ok := Groups[autoscaling.GroupName]; !ok {
Groups[autoscaling.GroupName] = TestGroup{
externalGroupVersion: unversioned.GroupVersion{Group: autoscaling.GroupName, Version: registered.GroupOrDie(autoscaling.GroupName).GroupVersion.Version},
internalGroupVersion: extensions.SchemeGroupVersion,
internalTypes: api.Scheme.KnownTypes(api.SchemeGroupVersion),
}
}
if _, ok := Groups[extensions.GroupName]; !ok {
Groups[extensions.GroupName] = TestGroup{
externalGroupVersion: unversioned.GroupVersion{Group: extensions.GroupName, Version: registered.GroupOrDie(extensions.GroupName).GroupVersion.Version},
internalGroupVersion: extensions.SchemeGroupVersion,
internalTypes: api.Scheme.KnownTypes(extensions.SchemeGroupVersion),
}
}
if _, ok := Groups[autoscaling.GroupName]; !ok {
internalTypes := make(map[string]reflect.Type)
for k, t := range api.Scheme.KnownTypes(extensions.SchemeGroupVersion) {
if k == "Scale" {
continue
}
internalTypes[k] = t
}
Groups[autoscaling.GroupName] = TestGroup{
externalGroupVersion: unversioned.GroupVersion{Group: autoscaling.GroupName, Version: registered.GroupOrDie(autoscaling.GroupName).GroupVersion.Version},
internalGroupVersion: extensions.SchemeGroupVersion,
internalTypes: internalTypes,
}
}
if _, ok := Groups[autoscaling.GroupName+"IntraGroup"]; !ok {
internalTypes := make(map[string]reflect.Type)
for k, t := range api.Scheme.KnownTypes(extensions.SchemeGroupVersion) {
if k == "Scale" {
internalTypes[k] = t
break
}
}
Groups[autoscaling.GroupName] = TestGroup{
externalGroupVersion: unversioned.GroupVersion{Group: autoscaling.GroupName, Version: registered.GroupOrDie(autoscaling.GroupName).GroupVersion.Version},
internalGroupVersion: autoscaling.SchemeGroupVersion,
internalTypes: internalTypes,
}
}
if _, ok := Groups[batch.GroupName]; !ok {
Groups[batch.GroupName] = TestGroup{
externalGroupVersion: unversioned.GroupVersion{Group: batch.GroupName, Version: registered.GroupOrDie(batch.GroupName).GroupVersion.Version},
internalGroupVersion: extensions.SchemeGroupVersion,
internalTypes: api.Scheme.KnownTypes(extensions.SchemeGroupVersion),
}
}
Default = Groups[api.GroupName]
Autoscaling = Groups[autoscaling.GroupName]
Batch = Groups[batch.GroupName]
Extensions = Groups[extensions.GroupName]
}
@ -105,6 +144,11 @@ func (g TestGroup) InternalGroupVersion() unversioned.GroupVersion {
return g.internalGroupVersion
}
// InternalTypes returns a map of internal API types' kind names to their Go types.
func (g TestGroup) InternalTypes() map[string]reflect.Type {
return g.internalTypes
}
// Codec returns the codec for the API version to test against, as set by the
// KUBE_TEST_API env var.
func (g TestGroup) Codec() runtime.Codec {
@ -218,6 +262,6 @@ func GetCodecForObject(obj runtime.Object) (runtime.Codec, error) {
return nil, fmt.Errorf("unexpected kind: %v", kind)
}
func NewTestGroup(external, internal unversioned.GroupVersion) TestGroup {
return TestGroup{external, internal}
func NewTestGroup(external, internal unversioned.GroupVersion, internalTypes map[string]reflect.Type) TestGroup {
return TestGroup{external, internal, internalTypes}
}

View file

@ -1,133 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testapi
import (
"encoding/json"
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
)
// TODO these tests don't add much value for testing things that have groups
func TestResourcePathWithPrefix(t *testing.T) {
testCases := []struct {
prefix string
resource string
namespace string
name string
expected string
}{
{"prefix", "resource", "mynamespace", "myresource", "/api/" + Default.GroupVersion().Version + "/prefix/namespaces/mynamespace/resource/myresource"},
{"prefix", "resource", "", "myresource", "/api/" + Default.GroupVersion().Version + "/prefix/resource/myresource"},
{"prefix", "resource", "mynamespace", "", "/api/" + Default.GroupVersion().Version + "/prefix/namespaces/mynamespace/resource"},
{"prefix", "resource", "", "", "/api/" + Default.GroupVersion().Version + "/prefix/resource"},
{"", "resource", "mynamespace", "myresource", "/api/" + Default.GroupVersion().Version + "/namespaces/mynamespace/resource/myresource"},
}
for _, item := range testCases {
if actual := Default.ResourcePathWithPrefix(item.prefix, item.resource, item.namespace, item.name); actual != item.expected {
t.Errorf("Expected: %s, got: %s for prefix: %s, resource: %s, namespace: %s and name: %s", item.expected, actual, item.prefix, item.resource, item.namespace, item.name)
}
}
}
func TestResourcePath(t *testing.T) {
testCases := []struct {
resource string
namespace string
name string
expected string
}{
{"resource", "mynamespace", "myresource", "/api/" + Default.GroupVersion().Version + "/namespaces/mynamespace/resource/myresource"},
{"resource", "", "myresource", "/api/" + Default.GroupVersion().Version + "/resource/myresource"},
{"resource", "mynamespace", "", "/api/" + Default.GroupVersion().Version + "/namespaces/mynamespace/resource"},
{"resource", "", "", "/api/" + Default.GroupVersion().Version + "/resource"},
}
for _, item := range testCases {
if actual := Default.ResourcePath(item.resource, item.namespace, item.name); actual != item.expected {
t.Errorf("Expected: %s, got: %s for resource: %s, namespace: %s and name: %s", item.expected, actual, item.resource, item.namespace, item.name)
}
}
}
var status = &unversioned.Status{
Status: unversioned.StatusFailure,
Code: 200,
Reason: unversioned.StatusReasonUnknown,
Message: "",
}
func TestV1EncodeDecodeStatus(t *testing.T) {
v1Codec := Default.Codec()
encoded, err := runtime.Encode(v1Codec, status)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
typeMeta := unversioned.TypeMeta{}
if err := json.Unmarshal(encoded, &typeMeta); err != nil {
t.Errorf("unexpected error: %v", err)
}
if typeMeta.Kind != "Status" {
t.Errorf("Kind is not set to \"Status\". Got %v", string(encoded))
}
if typeMeta.APIVersion != "v1" {
t.Errorf("APIVersion is not set to \"v1\". Got %v", string(encoded))
}
decoded, err := runtime.Decode(v1Codec, encoded)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if !reflect.DeepEqual(status, decoded) {
t.Errorf("expected: %#v, got: %#v", status, decoded)
}
}
func testEncodeDecodeStatus(t *testing.T, codec runtime.Codec) {
encoded, err := runtime.Encode(codec, status)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
typeMeta := unversioned.TypeMeta{}
if err := json.Unmarshal(encoded, &typeMeta); err != nil {
t.Errorf("unexpected error: %v", err)
}
if typeMeta.Kind != "Status" {
t.Errorf("Kind is not set to \"Status\". Got %s", encoded)
}
if typeMeta.APIVersion != "v1" {
t.Errorf("APIVersion is not set to \"\". Got %s", encoded)
}
decoded, err := runtime.Decode(codec, encoded)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if !reflect.DeepEqual(status, decoded) {
t.Errorf("expected: %v, got: %v", status, decoded)
}
}
func TestAutoscalingEncodeDecodeStatus(t *testing.T) {
testEncodeDecodeStatus(t, Autoscaling.Codec())
}
func TestExperimentalEncodeDecodeStatus(t *testing.T) {
testEncodeDecodeStatus(t, Extensions.Codec())
}

View file

@ -1,144 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package compat
import (
"encoding/json"
"fmt"
"os"
"reflect"
"regexp"
"strconv"
"strings"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/validation/field"
)
// Based on: https://github.com/openshift/origin/blob/master/pkg/api/compatibility_test.go
//
// TestCompatibility reencodes the input using the codec for the given
// version and checks for the presence of the expected keys and absent
// keys in the resulting JSON.
func TestCompatibility(
t *testing.T,
version unversioned.GroupVersion,
input []byte,
validator func(obj runtime.Object) field.ErrorList,
expectedKeys map[string]string,
absentKeys []string,
) {
// Decode
codec := api.Codecs.LegacyCodec(version)
obj, err := runtime.Decode(codec, input)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
// Validate
errs := validator(obj)
if len(errs) != 0 {
t.Fatalf("Unexpected validation errors: %v", errs)
}
// Encode
output, err := runtime.Encode(codec, obj)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
// Validate old and new fields are encoded
generic := map[string]interface{}{}
if err := json.Unmarshal(output, &generic); err != nil {
t.Fatalf("Unexpected error: %v", err)
}
hasError := false
for k, expectedValue := range expectedKeys {
keys := strings.Split(k, ".")
if actualValue, ok, err := getJSONValue(generic, keys...); err != nil || !ok {
t.Errorf("Unexpected error for %s: %v", k, err)
hasError = true
} else if !reflect.DeepEqual(expectedValue, fmt.Sprintf("%v", actualValue)) {
hasError = true
t.Errorf("Unexpected value for %v: expected %v, got %v", k, expectedValue, actualValue)
}
}
for _, absentKey := range absentKeys {
keys := strings.Split(absentKey, ".")
actualValue, ok, err := getJSONValue(generic, keys...)
if err == nil || ok {
t.Errorf("Unexpected value found for for key %s: %v", absentKey, actualValue)
hasError = true
}
}
if hasError {
printer := new(kubectl.JSONPrinter)
printer.PrintObj(obj, os.Stdout)
t.Logf("2: Encoded value: %#v", string(output))
}
}
func getJSONValue(data map[string]interface{}, keys ...string) (interface{}, bool, error) {
// No keys, current value is it
if len(keys) == 0 {
return data, true, nil
}
// Get the key (and optional index)
key := keys[0]
index := -1
if matches := regexp.MustCompile(`^(.*)\[(\d+)\]$`).FindStringSubmatch(key); len(matches) > 0 {
key = matches[1]
index, _ = strconv.Atoi(matches[2])
}
// Look up the value
value, ok := data[key]
if !ok {
return nil, false, fmt.Errorf("No key %s found", key)
}
// Get the indexed value if an index is specified
if index >= 0 {
valueSlice, ok := value.([]interface{})
if !ok {
return nil, false, fmt.Errorf("Key %s did not hold a slice", key)
}
if index >= len(valueSlice) {
return nil, false, fmt.Errorf("Index %d out of bounds for slice at key: %v", index, key)
}
value = valueSlice[index]
}
if len(keys) == 1 {
return value, true, nil
}
childData, ok := value.(map[string]interface{})
if !ok {
return nil, false, fmt.Errorf("Key %s did not hold a map", keys[0])
}
return getJSONValue(childData, keys[1:]...)
}

View file

@ -1,72 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/labels"
)
// TestSelectableFieldLabelConversions verifies that given resource have field
// label conversion defined for each its selectable field.
// fields contains selectable fields of the resource.
// labelMap maps deprecated labels to their canonical names.
func TestSelectableFieldLabelConversionsOfKind(t *testing.T, apiVersion string, kind string, fields labels.Set, labelMap map[string]string) {
badFieldLabels := []string{
"name",
".name",
"bad",
"metadata",
"foo.bar",
}
value := "value"
if len(fields) == 0 {
t.Logf("no selectable fields for kind %q, skipping", kind)
}
for label := range fields {
if label == "name" {
t.Logf("FIXME: \"name\" is deprecated by \"metadata.name\", it should be removed from selectable fields of kind=%s", kind)
continue
}
newLabel, newValue, err := api.Scheme.ConvertFieldLabel(apiVersion, kind, label, value)
if err != nil {
t.Errorf("kind=%s label=%s: got unexpected error: %v", kind, label, err)
} else {
expectedLabel := label
if l, exists := labelMap[label]; exists {
expectedLabel = l
}
if newLabel != expectedLabel {
t.Errorf("kind=%s label=%s: got unexpected label name (%q != %q)", kind, label, newLabel, expectedLabel)
}
if newValue != value {
t.Errorf("kind=%s label=%s: got unexpected new value (%q != %q)", kind, label, newValue, value)
}
}
}
for _, label := range badFieldLabels {
_, _, err := api.Scheme.ConvertFieldLabel(apiVersion, kind, label, "value")
if err == nil {
t.Errorf("kind=%s label=%s: got unexpected non-error", kind, label)
}
}
}

View file

@ -1,413 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"fmt"
"math/rand"
"reflect"
"strconv"
"testing"
docker "github.com/fsouza/go-dockerclient"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util/intstr"
"github.com/google/gofuzz"
)
// FuzzerFor can randomly populate api objects that are destined for version.
func FuzzerFor(t *testing.T, version unversioned.GroupVersion, src rand.Source) *fuzz.Fuzzer {
f := fuzz.New().NilChance(.5).NumElements(1, 1)
if src != nil {
f.RandSource(src)
}
f.Funcs(
func(j *int, c fuzz.Continue) {
*j = int(c.Int31())
},
func(j **int, c fuzz.Continue) {
if c.RandBool() {
i := int(c.Int31())
*j = &i
} else {
*j = nil
}
},
func(q *resource.Quantity, c fuzz.Continue) {
*q = *resource.NewQuantity(c.Int63n(1000), resource.DecimalExponent)
},
func(j *runtime.TypeMeta, c fuzz.Continue) {
// We have to customize the randomization of TypeMetas because their
// APIVersion and Kind must remain blank in memory.
j.APIVersion = ""
j.Kind = ""
},
func(j *unversioned.TypeMeta, c fuzz.Continue) {
// We have to customize the randomization of TypeMetas because their
// APIVersion and Kind must remain blank in memory.
j.APIVersion = ""
j.Kind = ""
},
func(j *api.ObjectMeta, c fuzz.Continue) {
j.Name = c.RandString()
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
j.SelfLink = c.RandString()
j.UID = types.UID(c.RandString())
j.GenerateName = c.RandString()
var sec, nsec int64
c.Fuzz(&sec)
c.Fuzz(&nsec)
j.CreationTimestamp = unversioned.Unix(sec, nsec).Rfc3339Copy()
},
func(j *api.ObjectReference, c fuzz.Continue) {
// We have to customize the randomization of TypeMetas because their
// APIVersion and Kind must remain blank in memory.
j.APIVersion = c.RandString()
j.Kind = c.RandString()
j.Namespace = c.RandString()
j.Name = c.RandString()
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
j.FieldPath = c.RandString()
},
func(j *unversioned.ListMeta, c fuzz.Continue) {
j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
j.SelfLink = c.RandString()
},
func(j *api.ListOptions, c fuzz.Continue) {
label, _ := labels.Parse("a=b")
j.LabelSelector = label
field, _ := fields.ParseSelector("a=b")
j.FieldSelector = field
},
func(j *api.PodExecOptions, c fuzz.Continue) {
j.Stdout = true
j.Stderr = true
},
func(j *api.PodAttachOptions, c fuzz.Continue) {
j.Stdout = true
j.Stderr = true
},
func(s *api.PodSpec, c fuzz.Continue) {
c.FuzzNoCustom(s)
// has a default value
ttl := int64(30)
if c.RandBool() {
ttl = int64(c.Uint32())
}
s.TerminationGracePeriodSeconds = &ttl
c.Fuzz(s.SecurityContext)
if s.SecurityContext == nil {
s.SecurityContext = new(api.PodSecurityContext)
}
},
func(j *api.PodPhase, c fuzz.Continue) {
statuses := []api.PodPhase{api.PodPending, api.PodRunning, api.PodFailed, api.PodUnknown}
*j = statuses[c.Rand.Intn(len(statuses))]
},
func(j *api.Binding, c fuzz.Continue) {
c.Fuzz(&j.ObjectMeta)
j.Target.Name = c.RandString()
},
func(j *api.ReplicationControllerSpec, c fuzz.Continue) {
c.FuzzNoCustom(j) // fuzz self without calling this function again
//j.TemplateRef = nil // this is required for round trip
},
func(j *extensions.DeploymentStrategy, c fuzz.Continue) {
c.FuzzNoCustom(j) // fuzz self without calling this function again
// Ensure that strategyType is one of valid values.
strategyTypes := []extensions.DeploymentStrategyType{extensions.RecreateDeploymentStrategyType, extensions.RollingUpdateDeploymentStrategyType}
j.Type = strategyTypes[c.Rand.Intn(len(strategyTypes))]
if j.Type != extensions.RollingUpdateDeploymentStrategyType {
j.RollingUpdate = nil
} else {
rollingUpdate := extensions.RollingUpdateDeployment{}
if c.RandBool() {
rollingUpdate.MaxUnavailable = intstr.FromInt(int(c.RandUint64()))
rollingUpdate.MaxSurge = intstr.FromInt(int(c.RandUint64()))
} else {
rollingUpdate.MaxSurge = intstr.FromString(fmt.Sprintf("%d%%", c.RandUint64()))
}
j.RollingUpdate = &rollingUpdate
}
},
func(j *extensions.JobSpec, c fuzz.Continue) {
c.FuzzNoCustom(j) // fuzz self without calling this function again
completions := int(c.Rand.Int31())
parallelism := int(c.Rand.Int31())
j.Completions = &completions
j.Parallelism = &parallelism
},
func(j *api.List, c fuzz.Continue) {
c.FuzzNoCustom(j) // fuzz self without calling this function again
// TODO: uncomment when round trip starts from a versioned object
if false { //j.Items == nil {
j.Items = []runtime.Object{}
}
},
func(j *runtime.Object, c fuzz.Continue) {
// TODO: uncomment when round trip starts from a versioned object
if true { //c.RandBool() {
*j = &runtime.Unknown{
// We do not set TypeMeta here because it is not carried through a round trip
RawJSON: []byte(`{"apiVersion":"unknown.group/unknown","kind":"Something","someKey":"someValue"}`),
}
} else {
types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}}
t := types[c.Rand.Intn(len(types))]
c.Fuzz(t)
*j = t
}
},
func(pb map[docker.Port][]docker.PortBinding, c fuzz.Continue) {
// This is necessary because keys with nil values get omitted.
// TODO: Is this a bug?
pb[docker.Port(c.RandString())] = []docker.PortBinding{
{c.RandString(), c.RandString()},
{c.RandString(), c.RandString()},
}
},
func(pm map[string]docker.PortMapping, c fuzz.Continue) {
// This is necessary because keys with nil values get omitted.
// TODO: Is this a bug?
pm[c.RandString()] = docker.PortMapping{
c.RandString(): c.RandString(),
}
},
func(q *api.ResourceRequirements, c fuzz.Continue) {
randomQuantity := func() resource.Quantity {
var q resource.Quantity
c.Fuzz(&q)
return q
}
q.Limits = make(api.ResourceList)
q.Requests = make(api.ResourceList)
cpuLimit := randomQuantity()
q.Limits[api.ResourceCPU] = *cpuLimit.Copy()
q.Requests[api.ResourceCPU] = *cpuLimit.Copy()
memoryLimit := randomQuantity()
q.Limits[api.ResourceMemory] = *memoryLimit.Copy()
q.Requests[api.ResourceMemory] = *memoryLimit.Copy()
storageLimit := randomQuantity()
q.Limits[api.ResourceStorage] = *storageLimit.Copy()
q.Requests[api.ResourceStorage] = *storageLimit.Copy()
},
func(q *api.LimitRangeItem, c fuzz.Continue) {
var cpuLimit resource.Quantity
c.Fuzz(&cpuLimit)
q.Type = api.LimitTypeContainer
q.Default = make(api.ResourceList)
q.Default[api.ResourceCPU] = *(cpuLimit.Copy())
q.DefaultRequest = make(api.ResourceList)
q.DefaultRequest[api.ResourceCPU] = *(cpuLimit.Copy())
q.Max = make(api.ResourceList)
q.Max[api.ResourceCPU] = *(cpuLimit.Copy())
q.Min = make(api.ResourceList)
q.Min[api.ResourceCPU] = *(cpuLimit.Copy())
q.MaxLimitRequestRatio = make(api.ResourceList)
q.MaxLimitRequestRatio[api.ResourceCPU] = resource.MustParse("10")
},
func(p *api.PullPolicy, c fuzz.Continue) {
policies := []api.PullPolicy{api.PullAlways, api.PullNever, api.PullIfNotPresent}
*p = policies[c.Rand.Intn(len(policies))]
},
func(rp *api.RestartPolicy, c fuzz.Continue) {
policies := []api.RestartPolicy{api.RestartPolicyAlways, api.RestartPolicyNever, api.RestartPolicyOnFailure}
*rp = policies[c.Rand.Intn(len(policies))]
},
// Only api.DownwardAPIVolumeFile needs to have a specific func since FieldRef has to be
// defaulted to a version otherwise roundtrip will fail
// For the remaining volume plugins the default fuzzer is enough.
func(m *api.DownwardAPIVolumeFile, c fuzz.Continue) {
m.Path = c.RandString()
versions := []string{"v1"}
m.FieldRef.APIVersion = versions[c.Rand.Intn(len(versions))]
m.FieldRef.FieldPath = c.RandString()
},
func(vs *api.VolumeSource, c fuzz.Continue) {
// Exactly one of the fields must be set.
v := reflect.ValueOf(vs).Elem()
i := int(c.RandUint64() % uint64(v.NumField()))
t := v.Field(i).Addr()
for v.Field(i).IsNil() {
c.Fuzz(t.Interface())
}
},
func(i *api.ISCSIVolumeSource, c fuzz.Continue) {
i.ISCSIInterface = c.RandString()
if i.ISCSIInterface == "" {
i.ISCSIInterface = "default"
}
},
func(d *api.DNSPolicy, c fuzz.Continue) {
policies := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault}
*d = policies[c.Rand.Intn(len(policies))]
},
func(p *api.Protocol, c fuzz.Continue) {
protocols := []api.Protocol{api.ProtocolTCP, api.ProtocolUDP}
*p = protocols[c.Rand.Intn(len(protocols))]
},
func(p *api.ServiceAffinity, c fuzz.Continue) {
types := []api.ServiceAffinity{api.ServiceAffinityClientIP, api.ServiceAffinityNone}
*p = types[c.Rand.Intn(len(types))]
},
func(p *api.ServiceType, c fuzz.Continue) {
types := []api.ServiceType{api.ServiceTypeClusterIP, api.ServiceTypeNodePort, api.ServiceTypeLoadBalancer}
*p = types[c.Rand.Intn(len(types))]
},
func(ct *api.Container, c fuzz.Continue) {
c.FuzzNoCustom(ct) // fuzz self without calling this function again
ct.TerminationMessagePath = "/" + ct.TerminationMessagePath // Must be non-empty
},
func(p *api.Probe, c fuzz.Continue) {
c.FuzzNoCustom(p)
// These fields have default values.
intFieldsWithDefaults := [...]string{"TimeoutSeconds", "PeriodSeconds", "SuccessThreshold", "FailureThreshold"}
v := reflect.ValueOf(p).Elem()
for _, field := range intFieldsWithDefaults {
f := v.FieldByName(field)
if f.Int() == 0 {
f.SetInt(1)
}
}
},
func(ev *api.EnvVar, c fuzz.Continue) {
ev.Name = c.RandString()
if c.RandBool() {
ev.Value = c.RandString()
} else {
ev.ValueFrom = &api.EnvVarSource{}
ev.ValueFrom.FieldRef = &api.ObjectFieldSelector{}
var versions []unversioned.GroupVersion
for _, testGroup := range testapi.Groups {
versions = append(versions, *testGroup.GroupVersion())
}
ev.ValueFrom.FieldRef.APIVersion = versions[c.Rand.Intn(len(versions))].String()
ev.ValueFrom.FieldRef.FieldPath = c.RandString()
}
},
func(sc *api.SecurityContext, c fuzz.Continue) {
c.FuzzNoCustom(sc) // fuzz self without calling this function again
if c.RandBool() {
priv := c.RandBool()
sc.Privileged = &priv
}
if c.RandBool() {
sc.Capabilities = &api.Capabilities{
Add: make([]api.Capability, 0),
Drop: make([]api.Capability, 0),
}
c.Fuzz(&sc.Capabilities.Add)
c.Fuzz(&sc.Capabilities.Drop)
}
},
func(s *api.Secret, c fuzz.Continue) {
c.FuzzNoCustom(s) // fuzz self without calling this function again
s.Type = api.SecretTypeOpaque
},
func(pv *api.PersistentVolume, c fuzz.Continue) {
c.FuzzNoCustom(pv) // fuzz self without calling this function again
types := []api.PersistentVolumePhase{api.VolumeAvailable, api.VolumePending, api.VolumeBound, api.VolumeReleased, api.VolumeFailed}
pv.Status.Phase = types[c.Rand.Intn(len(types))]
pv.Status.Message = c.RandString()
reclamationPolicies := []api.PersistentVolumeReclaimPolicy{api.PersistentVolumeReclaimRecycle, api.PersistentVolumeReclaimRetain}
pv.Spec.PersistentVolumeReclaimPolicy = reclamationPolicies[c.Rand.Intn(len(reclamationPolicies))]
},
func(pvc *api.PersistentVolumeClaim, c fuzz.Continue) {
c.FuzzNoCustom(pvc) // fuzz self without calling this function again
types := []api.PersistentVolumeClaimPhase{api.ClaimBound, api.ClaimPending}
pvc.Status.Phase = types[c.Rand.Intn(len(types))]
},
func(s *api.NamespaceSpec, c fuzz.Continue) {
s.Finalizers = []api.FinalizerName{api.FinalizerKubernetes}
},
func(s *api.NamespaceStatus, c fuzz.Continue) {
s.Phase = api.NamespaceActive
},
func(http *api.HTTPGetAction, c fuzz.Continue) {
c.FuzzNoCustom(http) // fuzz self without calling this function again
http.Path = "/" + http.Path // can't be blank
http.Scheme = "x" + http.Scheme // can't be blank
},
func(ss *api.ServiceSpec, c fuzz.Continue) {
c.FuzzNoCustom(ss) // fuzz self without calling this function again
if len(ss.Ports) == 0 {
// There must be at least 1 port.
ss.Ports = append(ss.Ports, api.ServicePort{})
c.Fuzz(&ss.Ports[0])
}
for i := range ss.Ports {
switch ss.Ports[i].TargetPort.Type {
case intstr.Int:
ss.Ports[i].TargetPort.IntVal = 1 + ss.Ports[i].TargetPort.IntVal%65535 // non-zero
case intstr.String:
ss.Ports[i].TargetPort.StrVal = "x" + ss.Ports[i].TargetPort.StrVal // non-empty
}
}
},
func(n *api.Node, c fuzz.Continue) {
c.FuzzNoCustom(n)
n.Spec.ExternalID = "external"
},
func(s *api.NodeStatus, c fuzz.Continue) {
c.FuzzNoCustom(s)
s.Allocatable = s.Capacity
},
func(s *extensions.APIVersion, c fuzz.Continue) {
// We can't use c.RandString() here because it may generate empty
// string, which will cause tests failure.
s.APIGroup = "something"
},
func(s *extensions.HorizontalPodAutoscalerSpec, c fuzz.Continue) {
c.FuzzNoCustom(s) // fuzz self without calling this function again
minReplicas := int(c.Rand.Int31())
s.MinReplicas = &minReplicas
s.CPUUtilization = &extensions.CPUTargetUtilization{TargetPercentage: int(int32(c.RandUint64()))}
},
func(s *extensions.SubresourceReference, c fuzz.Continue) {
c.FuzzNoCustom(s) // fuzz self without calling this function again
s.Subresource = "scale"
},
func(psp *extensions.PodSecurityPolicySpec, c fuzz.Continue) {
c.FuzzNoCustom(psp) // fuzz self without calling this function again
userTypes := []extensions.RunAsUserStrategy{extensions.RunAsUserStrategyMustRunAsNonRoot, extensions.RunAsUserStrategyMustRunAs, extensions.RunAsUserStrategyRunAsAny}
psp.RunAsUser.Type = userTypes[c.Rand.Intn(len(userTypes))]
seLinuxTypes := []extensions.SELinuxContextStrategy{extensions.SELinuxStrategyRunAsAny, extensions.SELinuxStrategyMustRunAs}
psp.SELinuxContext.Type = seLinuxTypes[c.Rand.Intn(len(seLinuxTypes))]
},
)
return f
}

View file

@ -1,32 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testing
import (
"k8s.io/kubernetes/pkg/api"
)
// DeepEqualSafePodSpec returns a PodSpec which is ready to be used with api.Semantic.DeepEqual
func DeepEqualSafePodSpec() api.PodSpec {
grace := int64(30)
return api.PodSpec{
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
TerminationGracePeriodSeconds: &grace,
SecurityContext: &api.PodSecurityContext{},
}
}

View file

@ -26953,13 +26953,14 @@ func (x *ReplicationControllerStatus) CodecEncodeSelf(e *codec1978.Encoder) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [2]bool
var yyq2 [3]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[1] = x.ObservedGeneration != 0
yyq2[1] = x.FullyLabeledReplicas != 0
yyq2[2] = x.ObservedGeneration != 0
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(2)
r.EncodeArrayStart(3)
} else {
yynn2 = 1
for _, b := range yyq2 {
@ -26996,7 +26997,7 @@ func (x *ReplicationControllerStatus) CodecEncodeSelf(e *codec1978.Encoder) {
_ = yym7
if false {
} else {
r.EncodeInt(int64(x.ObservedGeneration))
r.EncodeInt(int64(x.FullyLabeledReplicas))
}
} else {
r.EncodeInt(0)
@ -27004,11 +27005,36 @@ func (x *ReplicationControllerStatus) CodecEncodeSelf(e *codec1978.Encoder) {
} else {
if yyq2[1] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("observedGeneration"))
r.EncodeString(codecSelferC_UTF81234, string("fullyLabeledReplicas"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym8 := z.EncBinary()
_ = yym8
if false {
} else {
r.EncodeInt(int64(x.FullyLabeledReplicas))
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[2] {
yym10 := z.EncBinary()
_ = yym10
if false {
} else {
r.EncodeInt(int64(x.ObservedGeneration))
}
} else {
r.EncodeInt(0)
}
} else {
if yyq2[2] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("observedGeneration"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym11 := z.EncBinary()
_ = yym11
if false {
} else {
r.EncodeInt(int64(x.ObservedGeneration))
}
@ -27081,6 +27107,12 @@ func (x *ReplicationControllerStatus) codecDecodeSelfFromMap(l int, d *codec1978
} else {
x.Replicas = int(r.DecodeInt(codecSelferBitsize1234))
}
case "fullyLabeledReplicas":
if r.TryDecodeAsNil() {
x.FullyLabeledReplicas = 0
} else {
x.FullyLabeledReplicas = int(r.DecodeInt(codecSelferBitsize1234))
}
case "observedGeneration":
if r.TryDecodeAsNil() {
x.ObservedGeneration = 0
@ -27098,16 +27130,16 @@ func (x *ReplicationControllerStatus) codecDecodeSelfFromArray(l int, d *codec19
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj6 int
var yyb6 bool
var yyhl6 bool = l >= 0
yyj6++
if yyhl6 {
yyb6 = yyj6 > l
var yyj7 int
var yyb7 bool
var yyhl7 bool = l >= 0
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb6 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb6 {
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -27117,13 +27149,29 @@ func (x *ReplicationControllerStatus) codecDecodeSelfFromArray(l int, d *codec19
} else {
x.Replicas = int(r.DecodeInt(codecSelferBitsize1234))
}
yyj6++
if yyhl6 {
yyb6 = yyj6 > l
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb6 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb6 {
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.FullyLabeledReplicas = 0
} else {
x.FullyLabeledReplicas = int(r.DecodeInt(codecSelferBitsize1234))
}
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb7 = r.CheckBreak()
}
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -27134,17 +27182,17 @@ func (x *ReplicationControllerStatus) codecDecodeSelfFromArray(l int, d *codec19
x.ObservedGeneration = int64(r.DecodeInt(64))
}
for {
yyj6++
if yyhl6 {
yyb6 = yyj6 > l
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb6 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb6 {
if yyb7 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj6-1, "")
z.DecStructFieldNotFound(yyj7-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}
@ -44187,6 +44235,32 @@ func (x *LimitRangeList) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}
func (x ResourceQuotaScope) CodecEncodeSelf(e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
yym1 := z.EncBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.EncExt(x) {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x))
}
}
func (x *ResourceQuotaScope) CodecDecodeSelf(d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
yym1 := z.DecBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.DecExt(x) {
} else {
*((*string)(x)) = r.DecodeString()
}
}
func (x *ResourceQuotaSpec) CodecEncodeSelf(e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
@ -44201,13 +44275,14 @@ func (x *ResourceQuotaSpec) CodecEncodeSelf(e *codec1978.Encoder) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [1]bool
var yyq2 [2]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[0] = len(x.Hard) != 0
yyq2[1] = len(x.Scopes) != 0
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(1)
r.EncodeArrayStart(2)
} else {
yynn2 = 0
for _, b := range yyq2 {
@ -44241,6 +44316,39 @@ func (x *ResourceQuotaSpec) CodecEncodeSelf(e *codec1978.Encoder) {
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[1] {
if x.Scopes == nil {
r.EncodeNil()
} else {
yym7 := z.EncBinary()
_ = yym7
if false {
} else {
h.encSliceResourceQuotaScope(([]ResourceQuotaScope)(x.Scopes), e)
}
}
} else {
r.EncodeNil()
}
} else {
if yyq2[1] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("scopes"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
if x.Scopes == nil {
r.EncodeNil()
} else {
yym8 := z.EncBinary()
_ = yym8
if false {
} else {
h.encSliceResourceQuotaScope(([]ResourceQuotaScope)(x.Scopes), e)
}
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
@ -44309,6 +44417,18 @@ func (x *ResourceQuotaSpec) codecDecodeSelfFromMap(l int, d *codec1978.Decoder)
yyv4 := &x.Hard
yyv4.CodecDecodeSelf(d)
}
case "scopes":
if r.TryDecodeAsNil() {
x.Scopes = nil
} else {
yyv5 := &x.Scopes
yym6 := z.DecBinary()
_ = yym6
if false {
} else {
h.decSliceResourceQuotaScope((*[]ResourceQuotaScope)(yyv5), d)
}
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
@ -44320,16 +44440,16 @@ func (x *ResourceQuotaSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj5 int
var yyb5 bool
var yyhl5 bool = l >= 0
yyj5++
if yyhl5 {
yyb5 = yyj5 > l
var yyj7 int
var yyb7 bool
var yyhl7 bool = l >= 0
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb5 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb5 {
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -44337,21 +44457,43 @@ func (x *ResourceQuotaSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder
if r.TryDecodeAsNil() {
x.Hard = nil
} else {
yyv6 := &x.Hard
yyv6.CodecDecodeSelf(d)
yyv8 := &x.Hard
yyv8.CodecDecodeSelf(d)
}
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb7 = r.CheckBreak()
}
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Scopes = nil
} else {
yyv9 := &x.Scopes
yym10 := z.DecBinary()
_ = yym10
if false {
} else {
h.decSliceResourceQuotaScope((*[]ResourceQuotaScope)(yyv9), d)
}
}
for {
yyj5++
if yyhl5 {
yyb5 = yyj5 > l
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb5 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb5 {
if yyb7 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj5-1, "")
z.DecStructFieldNotFound(yyj7-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}
@ -51295,7 +51437,7 @@ func (x codecSelfer1234) decSliceReplicationController(v *[]ReplicationControlle
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 232)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 240)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
@ -53768,6 +53910,116 @@ func (x codecSelfer1234) decSliceLimitRange(v *[]LimitRange, d *codec1978.Decode
}
}
func (x codecSelfer1234) encSliceResourceQuotaScope(v []ResourceQuotaScope, e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
r.EncodeArrayStart(len(v))
for _, yyv1 := range v {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
yyv1.CodecEncodeSelf(e)
}
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
}
func (x codecSelfer1234) decSliceResourceQuotaScope(v *[]ResourceQuotaScope, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
yyv1 := *v
yyh1, yyl1 := z.DecSliceHelperStart()
var yyc1 bool
_ = yyc1
if yyl1 == 0 {
if yyv1 == nil {
yyv1 = []ResourceQuotaScope{}
yyc1 = true
} else if len(yyv1) != 0 {
yyv1 = yyv1[:0]
yyc1 = true
}
} else if yyl1 > 0 {
var yyrr1, yyrl1 int
var yyrt1 bool
_, _ = yyrl1, yyrt1
yyrr1 = yyl1 // len(yyv1)
if yyl1 > cap(yyv1) {
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 16)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
} else {
yyv1 = make([]ResourceQuotaScope, yyrl1)
}
} else {
yyv1 = make([]ResourceQuotaScope, yyrl1)
}
yyc1 = true
yyrr1 = len(yyv1)
} else if yyl1 != len(yyv1) {
yyv1 = yyv1[:yyl1]
yyc1 = true
}
yyj1 := 0
for ; yyj1 < yyrr1; yyj1++ {
yyh1.ElemContainerState(yyj1)
if r.TryDecodeAsNil() {
yyv1[yyj1] = ""
} else {
yyv1[yyj1] = ResourceQuotaScope(r.DecodeString())
}
}
if yyrt1 {
for ; yyj1 < yyl1; yyj1++ {
yyv1 = append(yyv1, "")
yyh1.ElemContainerState(yyj1)
if r.TryDecodeAsNil() {
yyv1[yyj1] = ""
} else {
yyv1[yyj1] = ResourceQuotaScope(r.DecodeString())
}
}
}
} else {
yyj1 := 0
for ; !r.CheckBreak(); yyj1++ {
if yyj1 >= len(yyv1) {
yyv1 = append(yyv1, "") // var yyz1 ResourceQuotaScope
yyc1 = true
}
yyh1.ElemContainerState(yyj1)
if yyj1 < len(yyv1) {
if r.TryDecodeAsNil() {
yyv1[yyj1] = ""
} else {
yyv1[yyj1] = ResourceQuotaScope(r.DecodeString())
}
} else {
z.DecSwallow()
}
}
if yyj1 < len(yyv1) {
yyv1 = yyv1[:yyj1]
yyc1 = true
} else if yyj1 == 0 && yyv1 == nil {
yyv1 = []ResourceQuotaScope{}
yyc1 = true
}
}
yyh1.End()
if yyc1 {
*v = yyv1
}
}
func (x codecSelfer1234) encSliceResourceQuota(v []ResourceQuota, e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
@ -53807,7 +54059,7 @@ func (x codecSelfer1234) decSliceResourceQuota(v *[]ResourceQuota, d *codec1978.
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 216)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 240)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]

View file

@ -98,7 +98,7 @@ type ObjectMeta struct {
ResourceVersion string `json:"resourceVersion,omitempty"`
// A sequence number representing a specific generation of the desired state.
// Currently only implemented by replication controllers.
// Populated by the system. Read-only.
Generation int64 `json:"generation,omitempty"`
// CreationTimestamp is a timestamp representing the server time when this object was
@ -441,10 +441,10 @@ const (
// Represents a Persistent Disk resource in Google Compute Engine.
//
// A GCE PD must exist and be formatted before mounting to a container.
// The disk must also be in the same GCE project and zone as the kubelet.
// A GCE PD can only be mounted as read/write once.
// GCE PDs support ownership management and SELinux relabeling.
// A GCE PD must exist before mounting to a container. The disk must
// also be in the same GCE project and zone as the kubelet. A GCE PD
// can only be mounted as read/write once or read-only many times. GCE
// PDs support ownership management and SELinux relabeling.
type GCEPersistentDiskVolumeSource struct {
// Unique name of the PD resource. Used to identify the disk in GCE
PDName string `json:"pdName"`
@ -523,10 +523,10 @@ type FlexVolumeSource struct {
// Represents a Persistent Disk resource in AWS.
//
// An AWS EBS disk must exist and be formatted before mounting to a container.
// The disk must also be in the same AWS zone as the kubelet.
// A AWS EBS disk can only be mounted as read/write once.
// AWS EBS volumes support ownership management and SELinux relabeling.
// An AWS EBS disk must exist before mounting to a container. The disk
// must also be in the same AWS zone as the kubelet. A AWS EBS disk
// can only be mounted as read/write once. AWS EBS volumes support
// ownership management and SELinux relabeling.
type AWSElasticBlockStoreVolumeSource struct {
// Unique id of the persistent disk resource. Used to identify the disk in AWS
VolumeID string `json:"volumeID"`
@ -623,10 +623,10 @@ type RBDVolumeSource struct {
ReadOnly bool `json:"readOnly,omitempty"`
}
// Represents a cinder volume resource in Openstack.
// A Cinder volume must exist and be formatted before mounting to a container.
// The volume must also be in the same region as the kubelet.
// Cinder volumes support ownership management and SELinux relabeling.
// Represents a cinder volume resource in Openstack. A Cinder volume
// must exist before mounting to a container. The volume must also be
// in the same region as the kubelet. Cinder volumes support ownership
// management and SELinux relabeling.
type CinderVolumeSource struct {
// Unique id of the volume used to identify the cinder volume
VolumeID string `json:"volumeID"`
@ -742,7 +742,7 @@ type VolumeMount struct {
Name string `json:"name"`
// Optional: Defaults to false (read-write).
ReadOnly bool `json:"readOnly,omitempty"`
// Required.
// Required. Must not contain ':'.
MountPath string `json:"mountPath"`
}
@ -1380,6 +1380,9 @@ type ReplicationControllerStatus struct {
// Replicas is the number of actual replicas.
Replicas int `json:"replicas"`
// The number of pods that have labels matching the labels of the pod template of the replication controller.
FullyLabeledReplicas int `json:"fullyLabeledReplicas,omitempty"`
// ObservedGeneration is the most recent generation observed by the controller.
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
}
@ -1526,8 +1529,10 @@ type ServicePort struct {
// Optional: The target port on pods selected by this service. If this
// is a string, it will be looked up as a named port in the target
// Pod's container ports. If this is not specified, the default value
// is the sames as the Port field (an identity map).
// Pod's container ports. If this is not specified, the value
// of the 'port' field is used (an identity map).
// This field is ignored for services with clusterIP=None, and should be
// omitted or set equal to the 'port' field.
TargetPort intstr.IntOrString `json:"targetPort"`
// The port on each node on which this service is exposed.
@ -2185,14 +2190,41 @@ const (
ResourceQuotas ResourceName = "resourcequotas"
// ResourceSecrets, number
ResourceSecrets ResourceName = "secrets"
// ResourceConfigMaps, number
ResourceConfigMaps ResourceName = "configmaps"
// ResourcePersistentVolumeClaims, number
ResourcePersistentVolumeClaims ResourceName = "persistentvolumeclaims"
// CPU request, in cores. (500m = .5 cores)
ResourceRequestsCPU ResourceName = "requests.cpu"
// Memory request, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
ResourceRequestsMemory ResourceName = "requests.memory"
// CPU limit, in cores. (500m = .5 cores)
ResourceLimitsCPU ResourceName = "limits.cpu"
// Memory limit, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
ResourceLimitsMemory ResourceName = "limits.memory"
)
// A ResourceQuotaScope defines a filter that must match each object tracked by a quota
type ResourceQuotaScope string
const (
// Match all pod objects where spec.activeDeadlineSeconds
ResourceQuotaScopeTerminating ResourceQuotaScope = "Terminating"
// Match all pod objects where !spec.activeDeadlineSeconds
ResourceQuotaScopeNotTerminating ResourceQuotaScope = "NotTerminating"
// Match all pod objects that have best effort quality of service
ResourceQuotaScopeBestEffort ResourceQuotaScope = "BestEffort"
// Match all pod objects that do not have best effort quality of service
ResourceQuotaScopeNotBestEffort ResourceQuotaScope = "NotBestEffort"
)
// ResourceQuotaSpec defines the desired hard limits to enforce for Quota
type ResourceQuotaSpec struct {
// Hard is the set of desired hard limits for each named resource
Hard ResourceList `json:"hard,omitempty"`
// A collection of filters that must match each object tracked by a quota.
// If not specified, the quota matches all objects.
Scopes []ResourceQuotaScope `json:"scopes,omitempty"`
}
// ResourceQuotaStatus defines the enforced hard limits and observed use

View file

@ -1,153 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned
import (
"encoding/json"
"testing"
"time"
"github.com/ghodss/yaml"
)
type DurationHolder struct {
D Duration `json:"d"`
}
func TestDurationMarshalYAML(t *testing.T) {
cases := []struct {
input Duration
result string
}{
{Duration{5 * time.Second}, "d: 5s\n"},
{Duration{2 * time.Minute}, "d: 2m0s\n"},
{Duration{time.Hour + 3*time.Millisecond}, "d: 1h0m0.003s\n"},
}
for _, c := range cases {
input := DurationHolder{c.input}
result, err := yaml.Marshal(&input)
if err != nil {
t.Errorf("Failed to marshal input: %q: %v", input, err)
}
if string(result) != c.result {
t.Errorf("Failed to marshal input: %q: expected %q, got %q", input, c.result, string(result))
}
}
}
func TestDurationUnmarshalYAML(t *testing.T) {
cases := []struct {
input string
result Duration
}{
{"d: 0s\n", Duration{}},
{"d: 5s\n", Duration{5 * time.Second}},
{"d: 2m0s\n", Duration{2 * time.Minute}},
{"d: 1h0m0.003s\n", Duration{time.Hour + 3*time.Millisecond}},
// Units with zero values can optionally be dropped
{"d: 2m\n", Duration{2 * time.Minute}},
{"d: 1h0.003s\n", Duration{time.Hour + 3*time.Millisecond}},
}
for _, c := range cases {
var result DurationHolder
if err := yaml.Unmarshal([]byte(c.input), &result); err != nil {
t.Errorf("Failed to unmarshal input %q: %v", c.input, err)
}
if result.D != c.result {
t.Errorf("Failed to unmarshal input %q: expected %q, got %q", c.input, c.result, result)
}
}
}
func TestDurationMarshalJSON(t *testing.T) {
cases := []struct {
input Duration
result string
}{
{Duration{5 * time.Second}, `{"d":"5s"}`},
{Duration{2 * time.Minute}, `{"d":"2m0s"}`},
{Duration{time.Hour + 3*time.Millisecond}, `{"d":"1h0m0.003s"}`},
}
for _, c := range cases {
input := DurationHolder{c.input}
result, err := json.Marshal(&input)
if err != nil {
t.Errorf("Failed to marshal input: %q: %v", input, err)
}
if string(result) != c.result {
t.Errorf("Failed to marshal input: %q: expected %q, got %q", input, c.result, string(result))
}
}
}
func TestDurationUnmarshalJSON(t *testing.T) {
cases := []struct {
input string
result Duration
}{
{`{"d":"0s"}`, Duration{}},
{`{"d":"5s"}`, Duration{5 * time.Second}},
{`{"d":"2m0s"}`, Duration{2 * time.Minute}},
{`{"d":"1h0m0.003s"}`, Duration{time.Hour + 3*time.Millisecond}},
// Units with zero values can optionally be dropped
{`{"d":"2m"}`, Duration{2 * time.Minute}},
{`{"d":"1h0.003s"}`, Duration{time.Hour + 3*time.Millisecond}},
}
for _, c := range cases {
var result DurationHolder
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
t.Errorf("Failed to unmarshal input %q: %v", c.input, err)
}
if result.D != c.result {
t.Errorf("Failed to unmarshal input %q: expected %q, got %q", c.input, c.result, result)
}
}
}
func TestDurationMarshalJSONUnmarshalYAML(t *testing.T) {
cases := []struct {
input Duration
}{
{Duration{}},
{Duration{5 * time.Second}},
{Duration{2 * time.Minute}},
{Duration{time.Hour + 3*time.Millisecond}},
}
for i, c := range cases {
input := DurationHolder{c.input}
jsonMarshalled, err := json.Marshal(&input)
if err != nil {
t.Errorf("%d-1: Failed to marshal input: '%v': %v", i, input, err)
}
var result DurationHolder
if err := yaml.Unmarshal(jsonMarshalled, &result); err != nil {
t.Errorf("%d-2: Failed to unmarshal '%+v': %v", i, string(jsonMarshalled), err)
}
if input.D != result.D {
t.Errorf("%d-4: Failed to marshal input '%#v': got %#v", i, input, result)
}
}
}

View file

@ -22,6 +22,21 @@ import (
"strings"
)
// ParseResourceArg takes the common style of string which may be either `resource.group.com` or `resource.version.group.com`
// and parses it out into both possibilities. This code takes no responsibility for knowing which representation was intended
// but with a knowledge of all GroupVersions, calling code can take a very good guess. If there are only two segments, then
// `*GroupVersionResource` is nil.
// `resource.group.com` -> `group=com, version=group, resource=resource` and `group=group.com, resource=resource`
func ParseResourceArg(arg string) (*GroupVersionResource, GroupResource) {
var gvr *GroupVersionResource
s := strings.SplitN(arg, ".", 3)
if len(s) == 3 {
gvr = &GroupVersionResource{Group: s[2], Version: s[1], Resource: s[0]}
}
return gvr, ParseGroupResource(arg)
}
// GroupResource specifies a Group and a Resource, but does not force a version. This is useful for identifying
// concepts during lookup stages without having partially valid types
//
@ -46,6 +61,17 @@ func (gr *GroupResource) String() string {
return gr.Resource + "." + gr.Group
}
// ParseGroupResource turns "resource.group" string into a GroupResource struct. Empty strings are allowed
// for each field.
func ParseGroupResource(gr string) GroupResource {
s := strings.SplitN(gr, ".", 2)
if len(s) == 1 {
return GroupResource{Resource: s[0]}
}
return GroupResource{Group: s[1], Resource: s[0]}
}
// GroupVersionResource unambiguously identifies a resource. It doesn't anonymously include GroupVersion
// to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling
//

View file

@ -1,78 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned
import (
"encoding/json"
"reflect"
"testing"
"github.com/ugorji/go/codec"
)
type GroupVersionHolder struct {
GV GroupVersion `json:"val"`
}
func TestGroupVersionUnmarshalJSON(t *testing.T) {
cases := []struct {
input []byte
expect GroupVersion
}{
{[]byte(`{"val": "v1"}`), GroupVersion{"", "v1"}},
{[]byte(`{"val": "extensions/v1beta1"}`), GroupVersion{"extensions", "v1beta1"}},
}
for _, c := range cases {
var result GroupVersionHolder
// test golang lib's JSON codec
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
t.Errorf("JSON codec failed to unmarshal input '%v': %v", c.input, err)
}
if !reflect.DeepEqual(result.GV, c.expect) {
t.Errorf("JSON codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV)
}
// test the Ugorji codec
if err := codec.NewDecoderBytes(c.input, new(codec.JsonHandle)).Decode(&result); err != nil {
t.Errorf("Ugorji codec failed to unmarshal input '%v': %v", c.input, err)
}
if !reflect.DeepEqual(result.GV, c.expect) {
t.Errorf("Ugorji codec failed to unmarshal input '%s': expected %+v, got %+v", c.input, c.expect, result.GV)
}
}
}
func TestGroupVersionMarshalJSON(t *testing.T) {
cases := []struct {
input GroupVersion
expect []byte
}{
{GroupVersion{"", "v1"}, []byte(`{"val":"v1"}`)},
{GroupVersion{"extensions", "v1beta1"}, []byte(`{"val":"extensions/v1beta1"}`)},
}
for _, c := range cases {
input := GroupVersionHolder{c.input}
result, err := json.Marshal(&input)
if err != nil {
t.Errorf("Failed to marshal input '%v': %v", input, err)
}
if !reflect.DeepEqual(result, c.expect) {
t.Errorf("Failed to marshal input '%+v': expected: %s, got: %s", input, c.expect, result)
}
}
}

View file

@ -25,6 +25,7 @@ import (
// LabelSelectorAsSelector converts the LabelSelector api type into a struct that implements
// labels.Selector
// Note: This function should be kept in sync with the selector methods in pkg/labels/selector.go
func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) {
if ps == nil {
return labels.Nothing(), nil
@ -34,7 +35,7 @@ func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) {
}
selector := labels.NewSelector()
for k, v := range ps.MatchLabels {
r, err := labels.NewRequirement(k, labels.InOperator, sets.NewString(v))
r, err := labels.NewRequirement(k, labels.EqualsOperator, sets.NewString(v))
if err != nil {
return nil, err
}
@ -63,6 +64,55 @@ func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) {
return selector, nil
}
// ParseToLabelSelector parses a string representing a selector into a LabelSelector object.
// Note: This function should be kept in sync with the parser in pkg/labels/selector.go
func ParseToLabelSelector(selector string) (*LabelSelector, error) {
reqs, err := labels.ParseToRequirements(selector)
if err != nil {
return nil, fmt.Errorf("couldn't parse the selector string \"%s\": %v", selector, err)
}
labelSelector := &LabelSelector{
MatchLabels: map[string]string{},
MatchExpressions: []LabelSelectorRequirement{},
}
for _, req := range reqs {
var op LabelSelectorOperator
switch req.Operator() {
case labels.EqualsOperator, labels.DoubleEqualsOperator:
vals := req.Values()
if vals.Len() != 1 {
return nil, fmt.Errorf("equals operator must have exactly one value")
}
val, ok := vals.PopAny()
if !ok {
return nil, fmt.Errorf("equals operator has exactly one value but it cannot be retrieved")
}
labelSelector.MatchLabels[req.Key()] = val
continue
case labels.InOperator:
op = LabelSelectorOpIn
case labels.NotInOperator:
op = LabelSelectorOpNotIn
case labels.ExistsOperator:
op = LabelSelectorOpExists
case labels.DoesNotExistOperator:
op = LabelSelectorOpDoesNotExist
case labels.GreaterThanOperator, labels.LessThanOperator:
// Adding a separate case for these operators to indicate that this is deliberate
return nil, fmt.Errorf("%q isn't supported in label selectors", req.Operator())
default:
return nil, fmt.Errorf("%q is not a valid label selector operator", req.Operator())
}
labelSelector.MatchExpressions = append(labelSelector.MatchExpressions, LabelSelectorRequirement{
Key: req.Key(),
Operator: op,
Values: req.Values().List(),
})
}
return labelSelector, nil
}
// SetAsLabelSelector converts the labels.Set object into a LabelSelector api object.
func SetAsLabelSelector(ls labels.Set) *LabelSelector {
if ls == nil {
@ -92,3 +142,13 @@ func FormatLabelSelector(labelSelector *LabelSelector) string {
}
return l
}
func ExtractGroupVersions(l *APIGroupList) []string {
var groupVersions []string
for _, g := range l.Groups {
for _, gv := range g.Versions {
groupVersions = append(groupVersions, gv.GroupVersion)
}
}
return groupVersions
}

View file

@ -1,83 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned
import (
"reflect"
"testing"
"k8s.io/kubernetes/pkg/labels"
)
func TestLabelSelectorAsSelector(t *testing.T) {
matchLabels := map[string]string{"foo": "bar"}
matchExpressions := []LabelSelectorRequirement{{
Key: "baz",
Operator: LabelSelectorOpIn,
Values: []string{"qux", "norf"},
}}
mustParse := func(s string) labels.Selector {
out, e := labels.Parse(s)
if e != nil {
panic(e)
}
return out
}
tc := []struct {
in *LabelSelector
out labels.Selector
expectErr bool
}{
{in: nil, out: labels.Nothing()},
{in: &LabelSelector{}, out: labels.Everything()},
{
in: &LabelSelector{MatchLabels: matchLabels},
out: mustParse("foo in (bar)"),
},
{
in: &LabelSelector{MatchExpressions: matchExpressions},
out: mustParse("baz in (norf,qux)"),
},
{
in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions},
out: mustParse("foo in (bar),baz in (norf,qux)"),
},
{
in: &LabelSelector{
MatchExpressions: []LabelSelectorRequirement{{
Key: "baz",
Operator: LabelSelectorOpExists,
Values: []string{"qux", "norf"},
}},
},
expectErr: true,
},
}
for i, tc := range tc {
out, err := LabelSelectorAsSelector(tc.in)
if err == nil && tc.expectErr {
t.Errorf("[%v]expected error but got none.", i)
}
if err != nil && !tc.expectErr {
t.Errorf("[%v]did not expect error but got: %v", i, err)
}
if !reflect.DeepEqual(out, tc.out) {
t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out)
}
}
}

View file

@ -97,6 +97,27 @@ func (t *Time) UnmarshalJSON(b []byte) error {
return nil
}
// UnmarshalQueryParameter converts from a URL query parameter value to an object
func (t *Time) UnmarshalQueryParameter(str string) error {
if len(str) == 0 {
t.Time = time.Time{}
return nil
}
// Tolerate requests from older clients that used JSON serialization to build query params
if len(str) == 4 && str == "null" {
t.Time = time.Time{}
return nil
}
pt, err := time.Parse(time.RFC3339, str)
if err != nil {
return err
}
t.Time = pt.Local()
return nil
}
// MarshalJSON implements the json.Marshaler interface.
func (t Time) MarshalJSON() ([]byte, error) {
if t.IsZero() {
@ -107,6 +128,16 @@ func (t Time) MarshalJSON() ([]byte, error) {
return json.Marshal(t.UTC().Format(time.RFC3339))
}
// MarshalQueryParameter converts to a URL query parameter value
func (t Time) MarshalQueryParameter() (string, error) {
if t.IsZero() {
// Encode unset/nil objects as an empty string
return "", nil
}
return t.UTC().Format(time.RFC3339), nil
}
// Fuzz satisfies fuzz.Interface.
func (t *Time) Fuzz(c fuzz.Continue) {
if t == nil {

View file

@ -1,147 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned
import (
"encoding/json"
"testing"
"time"
"github.com/ghodss/yaml"
)
type TimeHolder struct {
T Time `json:"t"`
}
func TestTimeMarshalYAML(t *testing.T) {
cases := []struct {
input Time
result string
}{
{Time{}, "t: null\n"},
{Date(1998, time.May, 5, 1, 5, 5, 50, time.FixedZone("test", -4*60*60)), "t: 1998-05-05T05:05:05Z\n"},
{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "t: 1998-05-05T05:05:05Z\n"},
}
for _, c := range cases {
input := TimeHolder{c.input}
result, err := yaml.Marshal(&input)
if err != nil {
t.Errorf("Failed to marshal input: '%v': %v", input, err)
}
if string(result) != c.result {
t.Errorf("Failed to marshal input: '%v': expected %+v, got %q", input, c.result, string(result))
}
}
}
func TestTimeUnmarshalYAML(t *testing.T) {
cases := []struct {
input string
result Time
}{
{"t: null\n", Time{}},
{"t: 1998-05-05T05:05:05Z\n", Time{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC).Local()}},
}
for _, c := range cases {
var result TimeHolder
if err := yaml.Unmarshal([]byte(c.input), &result); err != nil {
t.Errorf("Failed to unmarshal input '%v': %v", c.input, err)
}
if result.T != c.result {
t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result)
}
}
}
func TestTimeMarshalJSON(t *testing.T) {
cases := []struct {
input Time
result string
}{
{Time{}, "{\"t\":null}"},
{Date(1998, time.May, 5, 5, 5, 5, 50, time.UTC), "{\"t\":\"1998-05-05T05:05:05Z\"}"},
{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "{\"t\":\"1998-05-05T05:05:05Z\"}"},
}
for _, c := range cases {
input := TimeHolder{c.input}
result, err := json.Marshal(&input)
if err != nil {
t.Errorf("Failed to marshal input: '%v': %v", input, err)
}
if string(result) != c.result {
t.Errorf("Failed to marshal input: '%v': expected %+v, got %q", input, c.result, string(result))
}
}
}
func TestTimeUnmarshalJSON(t *testing.T) {
cases := []struct {
input string
result Time
}{
{"{\"t\":null}", Time{}},
{"{\"t\":\"1998-05-05T05:05:05Z\"}", Time{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC).Local()}},
}
for _, c := range cases {
var result TimeHolder
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
t.Errorf("Failed to unmarshal input '%v': %v", c.input, err)
}
if result.T != c.result {
t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result)
}
}
}
func TestTimeMarshalJSONUnmarshalYAML(t *testing.T) {
cases := []struct {
input Time
}{
{Time{}},
{Date(1998, time.May, 5, 5, 5, 5, 50, time.Local).Rfc3339Copy()},
{Date(1998, time.May, 5, 5, 5, 5, 0, time.Local).Rfc3339Copy()},
}
for i, c := range cases {
input := TimeHolder{c.input}
jsonMarshalled, err := json.Marshal(&input)
if err != nil {
t.Errorf("%d-1: Failed to marshal input: '%v': %v", i, input, err)
}
var result TimeHolder
err = yaml.Unmarshal(jsonMarshalled, &result)
if err != nil {
t.Errorf("%d-2: Failed to unmarshal '%+v': %v", i, string(jsonMarshalled), err)
}
iN, iO := input.T.Zone()
oN, oO := result.T.Zone()
if iN != oN || iO != oO {
t.Errorf("%d-3: Time zones differ before and after serialization %s:%d %s:%d", i, iN, iO, oN, oO)
}
if input.T.UnixNano() != result.T.UnixNano() {
t.Errorf("%d-4: Failed to marshal input '%#v': got %#v", i, input, result)
}
}
}

View file

@ -35,13 +35,13 @@ type TypeMeta struct {
// Servers may infer this from the endpoint the client submits requests to.
// Cannot be updated.
// In CamelCase.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds
// More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds
Kind string `json:"kind,omitempty"`
// APIVersion defines the versioned schema of this representation of an object.
// Servers should convert recognized schemas to the latest internal value, and
// may reject unrecognized values.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources
// More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#resources
APIVersion string `json:"apiVersion,omitempty"`
}
@ -58,7 +58,7 @@ type ListMeta struct {
// Value must be treated as opaque by clients and passed unmodified back to the server.
// Populated by the system.
// Read-only.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#concurrency-control-and-consistency
// More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#concurrency-control-and-consistency
ResourceVersion string `json:"resourceVersion,omitempty"`
}
@ -75,12 +75,12 @@ type ExportOptions struct {
type Status struct {
TypeMeta `json:",inline"`
// Standard list metadata.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds
// More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds
ListMeta `json:"metadata,omitempty"`
// Status of the operation.
// One of: "Success" or "Failure".
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status
// More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status
Status string `json:"status,omitempty"`
// A human-readable description of the status of this operation.
Message string `json:"message,omitempty"`
@ -112,7 +112,7 @@ type StatusDetails struct {
Group string `json:"group,omitempty"`
// The kind attribute of the resource associated with the status StatusReason.
// On some operations may differ from the requested resource Kind.
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds
// More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds
Kind string `json:"kind,omitempty"`
// The Causes array includes more details associated with the StatusReason
// failure. Not all StatusReasons may provide detailed causes.

View file

@ -16,7 +16,7 @@ limitations under the License.
package unversioned
// This file contains a collection of methods that can be used from go-resful to
// This file contains a collection of methods that can be used from go-restful to
// generate Swagger API documentation for its models. Please read this PR for more
// information on the implementation: https://github.com/emicklei/go-restful/pull/215
//
@ -123,7 +123,7 @@ func (LabelSelectorRequirement) SwaggerDoc() map[string]string {
var map_ListMeta = map[string]string{
"": "ListMeta describes metadata that synthetic resources must have, including lists and various status objects. A resource may have only one of {ObjectMeta, ListMeta}.",
"selfLink": "SelfLink is a URL representing this object. Populated by the system. Read-only.",
"resourceVersion": "String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#concurrency-control-and-consistency",
"resourceVersion": "String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#concurrency-control-and-consistency",
}
func (ListMeta) SwaggerDoc() map[string]string {
@ -159,8 +159,8 @@ func (ServerAddressByClientCIDR) SwaggerDoc() map[string]string {
var map_Status = map[string]string{
"": "Status is a return value for calls that don't return other objects.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"status": "Status of the operation. One of: \"Success\" or \"Failure\". More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"status": "Status of the operation. One of: \"Success\" or \"Failure\". More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
"message": "A human-readable description of the status of this operation.",
"reason": "A machine-readable description of why this operation is in the \"Failure\" status. If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it.",
"details": "Extended data associated with the reason. Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type.",
@ -186,7 +186,7 @@ var map_StatusDetails = map[string]string{
"": "StatusDetails is a set of additional properties that MAY be set by the server to provide additional information about a response. The Reason field of a Status object defines what attributes will be set. Clients must ignore fields that do not match the defined type of each attribute, and should assume that any attribute may be empty, invalid, or under defined.",
"name": "The name attribute of the resource associated with the status StatusReason (when there is a single name which can be described).",
"group": "The group attribute of the resource associated with the status StatusReason.",
"kind": "The kind attribute of the resource associated with the status StatusReason. On some operations may differ from the requested resource Kind. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"kind": "The kind attribute of the resource associated with the status StatusReason. On some operations may differ from the requested resource Kind. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"causes": "The Causes array includes more details associated with the StatusReason failure. Not all StatusReasons may provide detailed causes.",
"retryAfterSeconds": "If specified, the time in seconds before the operation should be retried.",
}
@ -197,8 +197,8 @@ func (StatusDetails) SwaggerDoc() map[string]string {
var map_TypeMeta = map[string]string{
"": "TypeMeta describes an individual object in an API response or request with strings representing the type of the object and its API schema version. Structures that are versioned or persisted should inline TypeMeta.",
"kind": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"apiVersion": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources",
"kind": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"apiVersion": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#resources",
}
func (TypeMeta) SwaggerDoc() map[string]string {

View file

@ -1,53 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package validation
import (
"k8s.io/kubernetes/pkg/api/unversioned"
apivalidation "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/util/validation/field"
)
func ValidateLabelSelector(ps *unversioned.LabelSelector, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if ps == nil {
return allErrs
}
allErrs = append(allErrs, apivalidation.ValidateLabels(ps.MatchLabels, fldPath.Child("matchLabels"))...)
for i, expr := range ps.MatchExpressions {
allErrs = append(allErrs, ValidateLabelSelectorRequirement(expr, fldPath.Child("matchExpressions").Index(i))...)
}
return allErrs
}
func ValidateLabelSelectorRequirement(sr unversioned.LabelSelectorRequirement, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
switch sr.Operator {
case unversioned.LabelSelectorOpIn, unversioned.LabelSelectorOpNotIn:
if len(sr.Values) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("values"), "must be specified when `operator` is 'In' or 'NotIn'"))
}
case unversioned.LabelSelectorOpExists, unversioned.LabelSelectorOpDoesNotExist:
if len(sr.Values) > 0 {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("values"), "may not be specified when `operator` is 'Exists' or 'DoesNotExist'"))
}
default:
allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), sr.Operator, "not a valid selector operator"))
}
allErrs = append(allErrs, apivalidation.ValidateLabelName(sr.Key, fldPath.Child("key"))...)
return allErrs
}

View file

@ -1,63 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package util
import "testing"
func TestGetVersion(t *testing.T) {
testCases := []struct {
groupVersion string
output string
}{
{
"v1",
"v1",
},
{
"extensions/v1beta1",
"v1beta1",
},
}
for _, test := range testCases {
actual := GetVersion(test.groupVersion)
if test.output != actual {
t.Errorf("expect version: %s, got: %s\n", test.output, actual)
}
}
}
func TestGetGroup(t *testing.T) {
testCases := []struct {
groupVersion string
output string
}{
{
"v1",
"",
},
{
"extensions/v1beta1",
"extensions",
},
}
for _, test := range testCases {
actual := GetGroup(test.groupVersion)
if test.output != actual {
t.Errorf("expect version: %s, got: %s\n", test.output, actual)
}
}
}

View file

@ -1,229 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1_test
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testing/compat"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/validation/field"
)
func TestCompatibility_v1_PodSecurityContext(t *testing.T) {
cases := []struct {
name string
input string
expectedKeys map[string]string
absentKeys []string
}{
{
name: "hostNetwork = true",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostNetwork": true,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
expectedKeys: map[string]string{
"spec.hostNetwork": "true",
},
},
{
name: "hostNetwork = false",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostNetwork": false,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
absentKeys: []string{
"spec.hostNetwork",
},
},
{
name: "hostIPC = true",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostIPC": true,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
expectedKeys: map[string]string{
"spec.hostIPC": "true",
},
},
{
name: "hostIPC = false",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostIPC": false,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
absentKeys: []string{
"spec.hostIPC",
},
},
{
name: "hostPID = true",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostPID": true,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
expectedKeys: map[string]string{
"spec.hostPID": "true",
},
},
{
name: "hostPID = false",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"},
"spec": {
"hostPID": false,
"containers":[{
"name":"a",
"image":"my-container-image"
}]
}
}
`,
absentKeys: []string{
"spec.hostPID",
},
},
{
name: "reseting defaults for pre-v1.1 mirror pods",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{
"name":"my-pod-name",
"namespace":"my-pod-namespace",
"annotations": {
"kubernetes.io/config.mirror": "mirror"
}
},
"spec": {
"containers":[{
"name":"a",
"image":"my-container-image",
"resources": {
"limits": {
"cpu": "100m"
}
}
}]
}
}
`,
absentKeys: []string{
"spec.terminationGracePeriodSeconds",
"spec.containers[0].resources.requests",
},
},
{
name: "preserving defaults for v1.1+ mirror pods",
input: `
{
"kind":"Pod",
"apiVersion":"v1",
"metadata":{
"name":"my-pod-name",
"namespace":"my-pod-namespace",
"annotations": {
"kubernetes.io/config.mirror": "cbe924f710c7e26f7693d6a341bcfad0"
}
},
"spec": {
"containers":[{
"name":"a",
"image":"my-container-image",
"resources": {
"limits": {
"cpu": "100m"
}
}
}]
}
}
`,
expectedKeys: map[string]string{
"spec.terminationGracePeriodSeconds": "30",
"spec.containers[0].resources.requests": "map[cpu:100m]",
},
},
}
validator := func(obj runtime.Object) field.ErrorList {
return validation.ValidatePodSpec(&(obj.(*api.Pod).Spec), field.NewPath("spec"))
}
for _, tc := range cases {
t.Logf("Testing 1.0.0 backward compatibility for %v", tc.name)
compat.TestCompatibility(t, v1.SchemeGroupVersion, []byte(tc.input), validator, tc.expectedKeys, tc.absentKeys)
}
}

View file

@ -2598,6 +2598,7 @@ func autoConvert_api_ReplicationControllerStatus_To_v1_ReplicationControllerStat
defaulting.(func(*api.ReplicationControllerStatus))(in)
}
out.Replicas = int32(in.Replicas)
out.FullyLabeledReplicas = int32(in.FullyLabeledReplicas)
out.ObservedGeneration = in.ObservedGeneration
return nil
}
@ -2666,6 +2667,14 @@ func autoConvert_api_ResourceQuotaSpec_To_v1_ResourceQuotaSpec(in *api.ResourceQ
} else {
out.Hard = nil
}
if in.Scopes != nil {
out.Scopes = make([]ResourceQuotaScope, len(in.Scopes))
for i := range in.Scopes {
out.Scopes[i] = ResourceQuotaScope(in.Scopes[i])
}
} else {
out.Scopes = nil
}
return nil
}
@ -5828,6 +5837,7 @@ func autoConvert_v1_ReplicationControllerStatus_To_api_ReplicationControllerStat
defaulting.(func(*ReplicationControllerStatus))(in)
}
out.Replicas = int(in.Replicas)
out.FullyLabeledReplicas = int(in.FullyLabeledReplicas)
out.ObservedGeneration = in.ObservedGeneration
return nil
}
@ -5887,6 +5897,14 @@ func autoConvert_v1_ResourceQuotaSpec_To_api_ResourceQuotaSpec(in *ResourceQuota
if err := s.Convert(&in.Hard, &out.Hard, 0); err != nil {
return err
}
if in.Scopes != nil {
out.Scopes = make([]api.ResourceQuotaScope, len(in.Scopes))
for i := range in.Scopes {
out.Scopes[i] = api.ResourceQuotaScope(in.Scopes[i])
}
} else {
out.Scopes = nil
}
return nil
}

View file

@ -1,125 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1_test
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
versioned "k8s.io/kubernetes/pkg/api/v1"
)
// TestPodSpecConversion tests that ServiceAccount is an alias for
// ServiceAccountName.
func TestPodSpecConversion(t *testing.T) {
name, other := "foo", "bar"
// Test internal -> v1. Should have both alias (DeprecatedServiceAccount)
// and new field (ServiceAccountName).
i := &api.PodSpec{
ServiceAccountName: name,
}
v := versioned.PodSpec{}
if err := api.Scheme.Convert(i, &v); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if v.ServiceAccountName != name {
t.Fatalf("want v1.ServiceAccountName %q, got %q", name, v.ServiceAccountName)
}
if v.DeprecatedServiceAccount != name {
t.Fatalf("want v1.DeprecatedServiceAccount %q, got %q", name, v.DeprecatedServiceAccount)
}
// Test v1 -> internal. Either DeprecatedServiceAccount, ServiceAccountName,
// or both should translate to ServiceAccountName. ServiceAccountName wins
// if both are set.
testCases := []*versioned.PodSpec{
// New
{ServiceAccountName: name},
// Alias
{DeprecatedServiceAccount: name},
// Both: same
{ServiceAccountName: name, DeprecatedServiceAccount: name},
// Both: different
{ServiceAccountName: name, DeprecatedServiceAccount: other},
}
for k, v := range testCases {
got := api.PodSpec{}
err := api.Scheme.Convert(v, &got)
if err != nil {
t.Fatalf("unexpected error for case %d: %v", k, err)
}
if got.ServiceAccountName != name {
t.Fatalf("want api.ServiceAccountName %q, got %q", name, got.ServiceAccountName)
}
}
}
func TestResourceListConversion(t *testing.T) {
bigMilliQuantity := resource.NewQuantity(resource.MaxMilliValue, resource.DecimalSI)
bigMilliQuantity.Add(resource.MustParse("12345m"))
tests := []struct {
input versioned.ResourceList
expected api.ResourceList
}{
{ // No changes necessary.
input: versioned.ResourceList{
versioned.ResourceMemory: resource.MustParse("30M"),
versioned.ResourceCPU: resource.MustParse("100m"),
versioned.ResourceStorage: resource.MustParse("1G"),
},
expected: api.ResourceList{
api.ResourceMemory: resource.MustParse("30M"),
api.ResourceCPU: resource.MustParse("100m"),
api.ResourceStorage: resource.MustParse("1G"),
},
},
{ // Nano-scale values should be rounded up to milli-scale.
input: versioned.ResourceList{
versioned.ResourceCPU: resource.MustParse("3.000023m"),
versioned.ResourceMemory: resource.MustParse("500.000050m"),
},
expected: api.ResourceList{
api.ResourceCPU: resource.MustParse("4m"),
api.ResourceMemory: resource.MustParse("501m"),
},
},
{ // Large values should still be accurate.
input: versioned.ResourceList{
versioned.ResourceCPU: *bigMilliQuantity.Copy(),
versioned.ResourceStorage: *bigMilliQuantity.Copy(),
},
expected: api.ResourceList{
api.ResourceCPU: *bigMilliQuantity.Copy(),
api.ResourceStorage: *bigMilliQuantity.Copy(),
},
},
}
output := api.ResourceList{}
for i, test := range tests {
err := api.Scheme.Convert(&test.input, &output)
if err != nil {
t.Fatalf("unexpected error for case %d: %v", i, err)
}
if !api.Semantic.DeepEqual(test.expected, output) {
t.Errorf("unexpected conversion for case %d: Expected %+v; Got %+v", i, test.expected, output)
}
}
}

View file

@ -2031,6 +2031,7 @@ func deepCopy_v1_ReplicationControllerSpec(in ReplicationControllerSpec, out *Re
func deepCopy_v1_ReplicationControllerStatus(in ReplicationControllerStatus, out *ReplicationControllerStatus, c *conversion.Cloner) error {
out.Replicas = in.Replicas
out.FullyLabeledReplicas = in.FullyLabeledReplicas
out.ObservedGeneration = in.ObservedGeneration
return nil
}
@ -2084,6 +2085,14 @@ func deepCopy_v1_ResourceQuotaSpec(in ResourceQuotaSpec, out *ResourceQuotaSpec,
} else {
out.Hard = nil
}
if in.Scopes != nil {
out.Scopes = make([]ResourceQuotaScope, len(in.Scopes))
for i := range in.Scopes {
out.Scopes[i] = in.Scopes[i]
}
} else {
out.Scopes = nil
}
return nil
}

View file

@ -1,645 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1_test
import (
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
versioned "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/intstr"
)
func roundTrip(t *testing.T, obj runtime.Object) runtime.Object {
codec := api.Codecs.LegacyCodec(versioned.SchemeGroupVersion)
data, err := runtime.Encode(codec, obj)
if err != nil {
t.Errorf("%v\n %#v", err, obj)
return nil
}
obj2, err := runtime.Decode(codec, data)
if err != nil {
t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), obj)
return nil
}
obj3 := reflect.New(reflect.TypeOf(obj).Elem()).Interface().(runtime.Object)
err = api.Scheme.Convert(obj2, obj3)
if err != nil {
t.Errorf("%v\nSource: %#v", err, obj2)
return nil
}
return obj3
}
func TestSetDefaultReplicationController(t *testing.T) {
tests := []struct {
rc *versioned.ReplicationController
expectLabels bool
expectSelector bool
}{
{
rc: &versioned.ReplicationController{
Spec: versioned.ReplicationControllerSpec{
Template: &versioned.PodTemplateSpec{
ObjectMeta: versioned.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectLabels: true,
expectSelector: true,
},
{
rc: &versioned.ReplicationController{
ObjectMeta: versioned.ObjectMeta{
Labels: map[string]string{
"bar": "foo",
},
},
Spec: versioned.ReplicationControllerSpec{
Template: &versioned.PodTemplateSpec{
ObjectMeta: versioned.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectLabels: false,
expectSelector: true,
},
{
rc: &versioned.ReplicationController{
ObjectMeta: versioned.ObjectMeta{
Labels: map[string]string{
"bar": "foo",
},
},
Spec: versioned.ReplicationControllerSpec{
Selector: map[string]string{
"some": "other",
},
Template: &versioned.PodTemplateSpec{
ObjectMeta: versioned.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectLabels: false,
expectSelector: false,
},
{
rc: &versioned.ReplicationController{
Spec: versioned.ReplicationControllerSpec{
Selector: map[string]string{
"some": "other",
},
Template: &versioned.PodTemplateSpec{
ObjectMeta: versioned.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectLabels: true,
expectSelector: false,
},
}
for _, test := range tests {
rc := test.rc
obj2 := roundTrip(t, runtime.Object(rc))
rc2, ok := obj2.(*versioned.ReplicationController)
if !ok {
t.Errorf("unexpected object: %v", rc2)
t.FailNow()
}
if test.expectSelector != reflect.DeepEqual(rc2.Spec.Selector, rc2.Spec.Template.Labels) {
if test.expectSelector {
t.Errorf("expected: %v, got: %v", rc2.Spec.Template.Labels, rc2.Spec.Selector)
} else {
t.Errorf("unexpected equality: %v", rc.Spec.Selector)
}
}
if test.expectLabels != reflect.DeepEqual(rc2.Labels, rc2.Spec.Template.Labels) {
if test.expectLabels {
t.Errorf("expected: %v, got: %v", rc2.Spec.Template.Labels, rc2.Labels)
} else {
t.Errorf("unexpected equality: %v", rc.Labels)
}
}
}
}
func newInt(val int32) *int32 {
p := new(int32)
*p = val
return p
}
func TestSetDefaultReplicationControllerReplicas(t *testing.T) {
tests := []struct {
rc versioned.ReplicationController
expectReplicas int32
}{
{
rc: versioned.ReplicationController{
Spec: versioned.ReplicationControllerSpec{
Template: &versioned.PodTemplateSpec{
ObjectMeta: versioned.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectReplicas: 1,
},
{
rc: versioned.ReplicationController{
Spec: versioned.ReplicationControllerSpec{
Replicas: newInt(0),
Template: &versioned.PodTemplateSpec{
ObjectMeta: versioned.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectReplicas: 0,
},
{
rc: versioned.ReplicationController{
Spec: versioned.ReplicationControllerSpec{
Replicas: newInt(3),
Template: &versioned.PodTemplateSpec{
ObjectMeta: versioned.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
},
},
},
expectReplicas: 3,
},
}
for _, test := range tests {
rc := &test.rc
obj2 := roundTrip(t, runtime.Object(rc))
rc2, ok := obj2.(*versioned.ReplicationController)
if !ok {
t.Errorf("unexpected object: %v", rc2)
t.FailNow()
}
if rc2.Spec.Replicas == nil {
t.Errorf("unexpected nil Replicas")
} else if test.expectReplicas != *rc2.Spec.Replicas {
t.Errorf("expected: %d replicas, got: %d", test.expectReplicas, *rc2.Spec.Replicas)
}
}
}
func TestSetDefaultService(t *testing.T) {
svc := &versioned.Service{}
obj2 := roundTrip(t, runtime.Object(svc))
svc2 := obj2.(*versioned.Service)
if svc2.Spec.SessionAffinity != versioned.ServiceAffinityNone {
t.Errorf("Expected default session affinity type:%s, got: %s", versioned.ServiceAffinityNone, svc2.Spec.SessionAffinity)
}
if svc2.Spec.Type != versioned.ServiceTypeClusterIP {
t.Errorf("Expected default type:%s, got: %s", versioned.ServiceTypeClusterIP, svc2.Spec.Type)
}
}
func TestSetDefaultSecret(t *testing.T) {
s := &versioned.Secret{}
obj2 := roundTrip(t, runtime.Object(s))
s2 := obj2.(*versioned.Secret)
if s2.Type != versioned.SecretTypeOpaque {
t.Errorf("Expected secret type %v, got %v", versioned.SecretTypeOpaque, s2.Type)
}
}
func TestSetDefaultPersistentVolume(t *testing.T) {
pv := &versioned.PersistentVolume{}
obj2 := roundTrip(t, runtime.Object(pv))
pv2 := obj2.(*versioned.PersistentVolume)
if pv2.Status.Phase != versioned.VolumePending {
t.Errorf("Expected volume phase %v, got %v", versioned.VolumePending, pv2.Status.Phase)
}
if pv2.Spec.PersistentVolumeReclaimPolicy != versioned.PersistentVolumeReclaimRetain {
t.Errorf("Expected pv reclaim policy %v, got %v", versioned.PersistentVolumeReclaimRetain, pv2.Spec.PersistentVolumeReclaimPolicy)
}
}
func TestSetDefaultPersistentVolumeClaim(t *testing.T) {
pvc := &versioned.PersistentVolumeClaim{}
obj2 := roundTrip(t, runtime.Object(pvc))
pvc2 := obj2.(*versioned.PersistentVolumeClaim)
if pvc2.Status.Phase != versioned.ClaimPending {
t.Errorf("Expected claim phase %v, got %v", versioned.ClaimPending, pvc2.Status.Phase)
}
}
func TestSetDefaulEndpointsProtocol(t *testing.T) {
in := &versioned.Endpoints{Subsets: []versioned.EndpointSubset{
{Ports: []versioned.EndpointPort{{}, {Protocol: "UDP"}, {}}},
}}
obj := roundTrip(t, runtime.Object(in))
out := obj.(*versioned.Endpoints)
for i := range out.Subsets {
for j := range out.Subsets[i].Ports {
if in.Subsets[i].Ports[j].Protocol == "" {
if out.Subsets[i].Ports[j].Protocol != versioned.ProtocolTCP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Subsets[i].Ports[j].Protocol)
}
} else {
if out.Subsets[i].Ports[j].Protocol != in.Subsets[i].Ports[j].Protocol {
t.Errorf("Expected protocol %s, got %s", in.Subsets[i].Ports[j].Protocol, out.Subsets[i].Ports[j].Protocol)
}
}
}
}
}
func TestSetDefaulServiceTargetPort(t *testing.T) {
in := &versioned.Service{Spec: versioned.ServiceSpec{Ports: []versioned.ServicePort{{Port: 1234}}}}
obj := roundTrip(t, runtime.Object(in))
out := obj.(*versioned.Service)
if out.Spec.Ports[0].TargetPort != intstr.FromInt(1234) {
t.Errorf("Expected TargetPort to be defaulted, got %v", out.Spec.Ports[0].TargetPort)
}
in = &versioned.Service{Spec: versioned.ServiceSpec{Ports: []versioned.ServicePort{{Port: 1234, TargetPort: intstr.FromInt(5678)}}}}
obj = roundTrip(t, runtime.Object(in))
out = obj.(*versioned.Service)
if out.Spec.Ports[0].TargetPort != intstr.FromInt(5678) {
t.Errorf("Expected TargetPort to be unchanged, got %v", out.Spec.Ports[0].TargetPort)
}
}
func TestSetDefaultServicePort(t *testing.T) {
// Unchanged if set.
in := &versioned.Service{Spec: versioned.ServiceSpec{
Ports: []versioned.ServicePort{
{Protocol: "UDP", Port: 9376, TargetPort: intstr.FromString("p")},
{Protocol: "UDP", Port: 8675, TargetPort: intstr.FromInt(309)},
},
}}
out := roundTrip(t, runtime.Object(in)).(*versioned.Service)
if out.Spec.Ports[0].Protocol != versioned.ProtocolUDP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolUDP, out.Spec.Ports[0].Protocol)
}
if out.Spec.Ports[0].TargetPort != intstr.FromString("p") {
t.Errorf("Expected port %v, got %v", in.Spec.Ports[0].Port, out.Spec.Ports[0].TargetPort)
}
if out.Spec.Ports[1].Protocol != versioned.ProtocolUDP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolUDP, out.Spec.Ports[1].Protocol)
}
if out.Spec.Ports[1].TargetPort != intstr.FromInt(309) {
t.Errorf("Expected port %v, got %v", in.Spec.Ports[1].Port, out.Spec.Ports[1].TargetPort)
}
// Defaulted.
in = &versioned.Service{Spec: versioned.ServiceSpec{
Ports: []versioned.ServicePort{
{Protocol: "", Port: 9376, TargetPort: intstr.FromString("")},
{Protocol: "", Port: 8675, TargetPort: intstr.FromInt(0)},
},
}}
out = roundTrip(t, runtime.Object(in)).(*versioned.Service)
if out.Spec.Ports[0].Protocol != versioned.ProtocolTCP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Spec.Ports[0].Protocol)
}
if out.Spec.Ports[0].TargetPort != intstr.FromInt(int(in.Spec.Ports[0].Port)) {
t.Errorf("Expected port %v, got %v", in.Spec.Ports[0].Port, out.Spec.Ports[0].TargetPort)
}
if out.Spec.Ports[1].Protocol != versioned.ProtocolTCP {
t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Spec.Ports[1].Protocol)
}
if out.Spec.Ports[1].TargetPort != intstr.FromInt(int(in.Spec.Ports[1].Port)) {
t.Errorf("Expected port %v, got %v", in.Spec.Ports[1].Port, out.Spec.Ports[1].TargetPort)
}
}
func TestSetDefaultNamespace(t *testing.T) {
s := &versioned.Namespace{}
obj2 := roundTrip(t, runtime.Object(s))
s2 := obj2.(*versioned.Namespace)
if s2.Status.Phase != versioned.NamespaceActive {
t.Errorf("Expected phase %v, got %v", versioned.NamespaceActive, s2.Status.Phase)
}
}
func TestSetDefaultPodSpecHostNetwork(t *testing.T) {
portNum := int32(8080)
s := versioned.PodSpec{}
s.HostNetwork = true
s.Containers = []versioned.Container{
{
Ports: []versioned.ContainerPort{
{
ContainerPort: portNum,
},
},
},
}
pod := &versioned.Pod{
Spec: s,
}
obj2 := roundTrip(t, runtime.Object(pod))
pod2 := obj2.(*versioned.Pod)
s2 := pod2.Spec
hostPortNum := s2.Containers[0].Ports[0].HostPort
if hostPortNum != portNum {
t.Errorf("Expected container port to be defaulted, was made %d instead of %d", hostPortNum, portNum)
}
}
func TestSetDefaultNodeExternalID(t *testing.T) {
name := "node0"
n := &versioned.Node{}
n.Name = name
obj2 := roundTrip(t, runtime.Object(n))
n2 := obj2.(*versioned.Node)
if n2.Spec.ExternalID != name {
t.Errorf("Expected default External ID: %s, got: %s", name, n2.Spec.ExternalID)
}
if n2.Spec.ProviderID != "" {
t.Errorf("Expected empty default Cloud Provider ID, got: %s", n2.Spec.ProviderID)
}
}
func TestSetDefaultNodeStatusAllocatable(t *testing.T) {
capacity := versioned.ResourceList{
versioned.ResourceCPU: resource.MustParse("1000m"),
versioned.ResourceMemory: resource.MustParse("10G"),
}
allocatable := versioned.ResourceList{
versioned.ResourceCPU: resource.MustParse("500m"),
versioned.ResourceMemory: resource.MustParse("5G"),
}
tests := []struct {
capacity versioned.ResourceList
allocatable versioned.ResourceList
expectedAllocatable versioned.ResourceList
}{{ // Everything set, no defaulting.
capacity: capacity,
allocatable: allocatable,
expectedAllocatable: allocatable,
}, { // Allocatable set, no defaulting.
capacity: nil,
allocatable: allocatable,
expectedAllocatable: allocatable,
}, { // Capacity set, allocatable defaults to capacity.
capacity: capacity,
allocatable: nil,
expectedAllocatable: capacity,
}, { // Nothing set, allocatable "defaults" to capacity.
capacity: nil,
allocatable: nil,
expectedAllocatable: nil,
}}
copyResourceList := func(rl versioned.ResourceList) versioned.ResourceList {
if rl == nil {
return nil
}
copy := make(versioned.ResourceList, len(rl))
for k, v := range rl {
copy[k] = *v.Copy()
}
return copy
}
resourceListsEqual := func(a versioned.ResourceList, b versioned.ResourceList) bool {
if len(a) != len(b) {
return false
}
for k, v := range a {
vb, found := b[k]
if !found {
return false
}
if v.Cmp(vb) != 0 {
return false
}
}
return true
}
for i, testcase := range tests {
node := versioned.Node{
Status: versioned.NodeStatus{
Capacity: copyResourceList(testcase.capacity),
Allocatable: copyResourceList(testcase.allocatable),
},
}
node2 := roundTrip(t, runtime.Object(&node)).(*versioned.Node)
actual := node2.Status.Allocatable
expected := testcase.expectedAllocatable
if !resourceListsEqual(expected, actual) {
t.Errorf("[%d] Expected NodeStatus.Allocatable: %+v; Got: %+v", i, expected, actual)
}
}
}
func TestSetDefaultObjectFieldSelectorAPIVersion(t *testing.T) {
s := versioned.PodSpec{
Containers: []versioned.Container{
{
Env: []versioned.EnvVar{
{
ValueFrom: &versioned.EnvVarSource{
FieldRef: &versioned.ObjectFieldSelector{},
},
},
},
},
},
}
pod := &versioned.Pod{
Spec: s,
}
obj2 := roundTrip(t, runtime.Object(pod))
pod2 := obj2.(*versioned.Pod)
s2 := pod2.Spec
apiVersion := s2.Containers[0].Env[0].ValueFrom.FieldRef.APIVersion
if apiVersion != "v1" {
t.Errorf("Expected default APIVersion v1, got: %v", apiVersion)
}
}
func TestSetDefaultRequestsPod(t *testing.T) {
// verify we default if limits are specified
s := versioned.PodSpec{}
s.Containers = []versioned.Container{
{
Resources: versioned.ResourceRequirements{
Limits: versioned.ResourceList{
versioned.ResourceCPU: resource.MustParse("100m"),
},
},
},
}
pod := &versioned.Pod{
Spec: s,
}
output := roundTrip(t, runtime.Object(pod))
pod2 := output.(*versioned.Pod)
defaultRequest := pod2.Spec.Containers[0].Resources.Requests
requestValue := defaultRequest[versioned.ResourceCPU]
if requestValue.String() != "100m" {
t.Errorf("Expected request cpu: %s, got: %s", "100m", requestValue.String())
}
// verify we do nothing if no limits are specified
s = versioned.PodSpec{}
s.Containers = []versioned.Container{{}}
pod = &versioned.Pod{
Spec: s,
}
output = roundTrip(t, runtime.Object(pod))
pod2 = output.(*versioned.Pod)
defaultRequest = pod2.Spec.Containers[0].Resources.Requests
requestValue = defaultRequest[versioned.ResourceCPU]
if requestValue.String() != "0" {
t.Errorf("Expected 0 request value, got: %s", requestValue.String())
}
}
func TestDefaultRequestIsNotSetForReplicationController(t *testing.T) {
s := versioned.PodSpec{}
s.Containers = []versioned.Container{
{
Resources: versioned.ResourceRequirements{
Limits: versioned.ResourceList{
versioned.ResourceCPU: resource.MustParse("100m"),
},
},
},
}
rc := &versioned.ReplicationController{
Spec: versioned.ReplicationControllerSpec{
Replicas: newInt(3),
Template: &versioned.PodTemplateSpec{
ObjectMeta: versioned.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
},
},
Spec: s,
},
},
}
output := roundTrip(t, runtime.Object(rc))
rc2 := output.(*versioned.ReplicationController)
defaultRequest := rc2.Spec.Template.Spec.Containers[0].Resources.Requests
requestValue := defaultRequest[versioned.ResourceCPU]
if requestValue.String() != "0" {
t.Errorf("Expected 0 request value, got: %s", requestValue.String())
}
}
func TestSetDefaultLimitRangeItem(t *testing.T) {
limitRange := &versioned.LimitRange{
ObjectMeta: versioned.ObjectMeta{
Name: "test-defaults",
},
Spec: versioned.LimitRangeSpec{
Limits: []versioned.LimitRangeItem{{
Type: versioned.LimitTypeContainer,
Max: versioned.ResourceList{
versioned.ResourceCPU: resource.MustParse("100m"),
},
Min: versioned.ResourceList{
versioned.ResourceMemory: resource.MustParse("100Mi"),
},
Default: versioned.ResourceList{},
DefaultRequest: versioned.ResourceList{},
}},
},
}
output := roundTrip(t, runtime.Object(limitRange))
limitRange2 := output.(*versioned.LimitRange)
defaultLimit := limitRange2.Spec.Limits[0].Default
defaultRequest := limitRange2.Spec.Limits[0].DefaultRequest
// verify that default cpu was set to the max
defaultValue := defaultLimit[versioned.ResourceCPU]
if defaultValue.String() != "100m" {
t.Errorf("Expected default cpu: %s, got: %s", "100m", defaultValue.String())
}
// verify that default request was set to the limit
requestValue := defaultRequest[versioned.ResourceCPU]
if requestValue.String() != "100m" {
t.Errorf("Expected request cpu: %s, got: %s", "100m", requestValue.String())
}
// verify that if a min is provided, it will be the default if no limit is specified
requestMinValue := defaultRequest[versioned.ResourceMemory]
if requestMinValue.String() != "100Mi" {
t.Errorf("Expected request memory: %s, got: %s", "100Mi", requestMinValue.String())
}
}
func TestSetDefaultProbe(t *testing.T) {
originalProbe := versioned.Probe{}
expectedProbe := versioned.Probe{
InitialDelaySeconds: 0,
TimeoutSeconds: 1,
PeriodSeconds: 10,
SuccessThreshold: 1,
FailureThreshold: 3,
}
pod := &versioned.Pod{
Spec: versioned.PodSpec{
Containers: []versioned.Container{{LivenessProbe: &originalProbe}},
},
}
output := roundTrip(t, runtime.Object(pod)).(*versioned.Pod)
actualProbe := *output.Spec.Containers[0].LivenessProbe
if actualProbe != expectedProbe {
t.Errorf("Expected probe: %+v\ngot: %+v\n", expectedProbe, actualProbe)
}
}

View file

@ -26683,13 +26683,14 @@ func (x *ReplicationControllerStatus) CodecEncodeSelf(e *codec1978.Encoder) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [2]bool
var yyq2 [3]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[1] = x.ObservedGeneration != 0
yyq2[1] = x.FullyLabeledReplicas != 0
yyq2[2] = x.ObservedGeneration != 0
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(2)
r.EncodeArrayStart(3)
} else {
yynn2 = 1
for _, b := range yyq2 {
@ -26726,7 +26727,7 @@ func (x *ReplicationControllerStatus) CodecEncodeSelf(e *codec1978.Encoder) {
_ = yym7
if false {
} else {
r.EncodeInt(int64(x.ObservedGeneration))
r.EncodeInt(int64(x.FullyLabeledReplicas))
}
} else {
r.EncodeInt(0)
@ -26734,11 +26735,36 @@ func (x *ReplicationControllerStatus) CodecEncodeSelf(e *codec1978.Encoder) {
} else {
if yyq2[1] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("observedGeneration"))
r.EncodeString(codecSelferC_UTF81234, string("fullyLabeledReplicas"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym8 := z.EncBinary()
_ = yym8
if false {
} else {
r.EncodeInt(int64(x.FullyLabeledReplicas))
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[2] {
yym10 := z.EncBinary()
_ = yym10
if false {
} else {
r.EncodeInt(int64(x.ObservedGeneration))
}
} else {
r.EncodeInt(0)
}
} else {
if yyq2[2] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("observedGeneration"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym11 := z.EncBinary()
_ = yym11
if false {
} else {
r.EncodeInt(int64(x.ObservedGeneration))
}
@ -26811,6 +26837,12 @@ func (x *ReplicationControllerStatus) codecDecodeSelfFromMap(l int, d *codec1978
} else {
x.Replicas = int32(r.DecodeInt(32))
}
case "fullyLabeledReplicas":
if r.TryDecodeAsNil() {
x.FullyLabeledReplicas = 0
} else {
x.FullyLabeledReplicas = int32(r.DecodeInt(32))
}
case "observedGeneration":
if r.TryDecodeAsNil() {
x.ObservedGeneration = 0
@ -26828,16 +26860,16 @@ func (x *ReplicationControllerStatus) codecDecodeSelfFromArray(l int, d *codec19
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj6 int
var yyb6 bool
var yyhl6 bool = l >= 0
yyj6++
if yyhl6 {
yyb6 = yyj6 > l
var yyj7 int
var yyb7 bool
var yyhl7 bool = l >= 0
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb6 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb6 {
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -26847,13 +26879,29 @@ func (x *ReplicationControllerStatus) codecDecodeSelfFromArray(l int, d *codec19
} else {
x.Replicas = int32(r.DecodeInt(32))
}
yyj6++
if yyhl6 {
yyb6 = yyj6 > l
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb6 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb6 {
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.FullyLabeledReplicas = 0
} else {
x.FullyLabeledReplicas = int32(r.DecodeInt(32))
}
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb7 = r.CheckBreak()
}
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -26864,17 +26912,17 @@ func (x *ReplicationControllerStatus) codecDecodeSelfFromArray(l int, d *codec19
x.ObservedGeneration = int64(r.DecodeInt(64))
}
for {
yyj6++
if yyhl6 {
yyb6 = yyj6 > l
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb6 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb6 {
if yyb7 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj6-1, "")
z.DecStructFieldNotFound(yyj7-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}
@ -43999,6 +44047,32 @@ func (x *LimitRangeList) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}
func (x ResourceQuotaScope) CodecEncodeSelf(e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
yym1 := z.EncBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.EncExt(x) {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x))
}
}
func (x *ResourceQuotaScope) CodecDecodeSelf(d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
yym1 := z.DecBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.DecExt(x) {
} else {
*((*string)(x)) = r.DecodeString()
}
}
func (x *ResourceQuotaSpec) CodecEncodeSelf(e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
@ -44013,13 +44087,14 @@ func (x *ResourceQuotaSpec) CodecEncodeSelf(e *codec1978.Encoder) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [1]bool
var yyq2 [2]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[0] = len(x.Hard) != 0
yyq2[1] = len(x.Scopes) != 0
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(1)
r.EncodeArrayStart(2)
} else {
yynn2 = 0
for _, b := range yyq2 {
@ -44053,6 +44128,39 @@ func (x *ResourceQuotaSpec) CodecEncodeSelf(e *codec1978.Encoder) {
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[1] {
if x.Scopes == nil {
r.EncodeNil()
} else {
yym7 := z.EncBinary()
_ = yym7
if false {
} else {
h.encSliceResourceQuotaScope(([]ResourceQuotaScope)(x.Scopes), e)
}
}
} else {
r.EncodeNil()
}
} else {
if yyq2[1] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("scopes"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
if x.Scopes == nil {
r.EncodeNil()
} else {
yym8 := z.EncBinary()
_ = yym8
if false {
} else {
h.encSliceResourceQuotaScope(([]ResourceQuotaScope)(x.Scopes), e)
}
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
@ -44121,6 +44229,18 @@ func (x *ResourceQuotaSpec) codecDecodeSelfFromMap(l int, d *codec1978.Decoder)
yyv4 := &x.Hard
yyv4.CodecDecodeSelf(d)
}
case "scopes":
if r.TryDecodeAsNil() {
x.Scopes = nil
} else {
yyv5 := &x.Scopes
yym6 := z.DecBinary()
_ = yym6
if false {
} else {
h.decSliceResourceQuotaScope((*[]ResourceQuotaScope)(yyv5), d)
}
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
@ -44132,16 +44252,16 @@ func (x *ResourceQuotaSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj5 int
var yyb5 bool
var yyhl5 bool = l >= 0
yyj5++
if yyhl5 {
yyb5 = yyj5 > l
var yyj7 int
var yyb7 bool
var yyhl7 bool = l >= 0
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb5 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb5 {
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
@ -44149,21 +44269,43 @@ func (x *ResourceQuotaSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder
if r.TryDecodeAsNil() {
x.Hard = nil
} else {
yyv6 := &x.Hard
yyv6.CodecDecodeSelf(d)
yyv8 := &x.Hard
yyv8.CodecDecodeSelf(d)
}
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb7 = r.CheckBreak()
}
if yyb7 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Scopes = nil
} else {
yyv9 := &x.Scopes
yym10 := z.DecBinary()
_ = yym10
if false {
} else {
h.decSliceResourceQuotaScope((*[]ResourceQuotaScope)(yyv9), d)
}
}
for {
yyj5++
if yyhl5 {
yyb5 = yyj5 > l
yyj7++
if yyhl7 {
yyb7 = yyj7 > l
} else {
yyb5 = r.CheckBreak()
yyb7 = r.CheckBreak()
}
if yyb5 {
if yyb7 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj5-1, "")
z.DecStructFieldNotFound(yyj7-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}
@ -53826,6 +53968,116 @@ func (x codecSelfer1234) decSliceLimitRange(v *[]LimitRange, d *codec1978.Decode
}
}
func (x codecSelfer1234) encSliceResourceQuotaScope(v []ResourceQuotaScope, e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
r.EncodeArrayStart(len(v))
for _, yyv1 := range v {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
yyv1.CodecEncodeSelf(e)
}
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
}
func (x codecSelfer1234) decSliceResourceQuotaScope(v *[]ResourceQuotaScope, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
yyv1 := *v
yyh1, yyl1 := z.DecSliceHelperStart()
var yyc1 bool
_ = yyc1
if yyl1 == 0 {
if yyv1 == nil {
yyv1 = []ResourceQuotaScope{}
yyc1 = true
} else if len(yyv1) != 0 {
yyv1 = yyv1[:0]
yyc1 = true
}
} else if yyl1 > 0 {
var yyrr1, yyrl1 int
var yyrt1 bool
_, _ = yyrl1, yyrt1
yyrr1 = yyl1 // len(yyv1)
if yyl1 > cap(yyv1) {
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 16)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
} else {
yyv1 = make([]ResourceQuotaScope, yyrl1)
}
} else {
yyv1 = make([]ResourceQuotaScope, yyrl1)
}
yyc1 = true
yyrr1 = len(yyv1)
} else if yyl1 != len(yyv1) {
yyv1 = yyv1[:yyl1]
yyc1 = true
}
yyj1 := 0
for ; yyj1 < yyrr1; yyj1++ {
yyh1.ElemContainerState(yyj1)
if r.TryDecodeAsNil() {
yyv1[yyj1] = ""
} else {
yyv1[yyj1] = ResourceQuotaScope(r.DecodeString())
}
}
if yyrt1 {
for ; yyj1 < yyl1; yyj1++ {
yyv1 = append(yyv1, "")
yyh1.ElemContainerState(yyj1)
if r.TryDecodeAsNil() {
yyv1[yyj1] = ""
} else {
yyv1[yyj1] = ResourceQuotaScope(r.DecodeString())
}
}
}
} else {
yyj1 := 0
for ; !r.CheckBreak(); yyj1++ {
if yyj1 >= len(yyv1) {
yyv1 = append(yyv1, "") // var yyz1 ResourceQuotaScope
yyc1 = true
}
yyh1.ElemContainerState(yyj1)
if yyj1 < len(yyv1) {
if r.TryDecodeAsNil() {
yyv1[yyj1] = ""
} else {
yyv1[yyj1] = ResourceQuotaScope(r.DecodeString())
}
} else {
z.DecSwallow()
}
}
if yyj1 < len(yyv1) {
yyv1 = yyv1[:yyj1]
yyc1 = true
} else if yyj1 == 0 && yyv1 == nil {
yyv1 = []ResourceQuotaScope{}
yyc1 = true
}
}
yyh1.End()
if yyc1 {
*v = yyv1
}
}
func (x codecSelfer1234) encSliceResourceQuota(v []ResourceQuota, e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
@ -53865,7 +54117,7 @@ func (x codecSelfer1234) decSliceResourceQuota(v *[]ResourceQuota, d *codec1978.
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 216)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 240)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@ limitations under the License.
package v1
// This file contains a collection of methods that can be used from go-resful to
// This file contains a collection of methods that can be used from go-restful to
// generate Swagger API documentation for its models. Please read this PR for more
// information on the implementation: https://github.com/emicklei/go-restful/pull/215
//
@ -28,11 +28,11 @@ package v1
// AUTO-GENERATED FUNCTIONS START HERE
var map_AWSElasticBlockStoreVolumeSource = map[string]string{
"": "Represents a Persistent Disk resource in AWS.\n\nAn AWS EBS disk must exist and be formatted before mounting to a container. The disk must also be in the same AWS zone as the kubelet. An AWS EBS disk can only be mounted as read/write once. AWS EBS volumes support ownership management and SELinux relabeling.",
"volumeID": "Unique ID of the persistent disk resource in AWS (Amazon EBS volume). More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#awselasticblockstore",
"fsType": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#awselasticblockstore",
"": "Represents a Persistent Disk resource in AWS.\n\nAn AWS EBS disk must exist before mounting to a container. The disk must also be in the same AWS zone as the kubelet. An AWS EBS disk can only be mounted as read/write once. AWS EBS volumes support ownership management and SELinux relabeling.",
"volumeID": "Unique ID of the persistent disk resource in AWS (Amazon EBS volume). More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#awselasticblockstore",
"fsType": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#awselasticblockstore",
"partition": "The partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as \"1\". Similarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).",
"readOnly": "Specify \"true\" to force and set the ReadOnly property in VolumeMounts to \"true\". If omitted, the default is \"false\". More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#awselasticblockstore",
"readOnly": "Specify \"true\" to force and set the ReadOnly property in VolumeMounts to \"true\". If omitted, the default is \"false\". More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#awselasticblockstore",
}
func (AWSElasticBlockStoreVolumeSource) SwaggerDoc() map[string]string {
@ -61,7 +61,7 @@ func (AzureFileVolumeSource) SwaggerDoc() map[string]string {
var map_Binding = map[string]string{
"": "Binding ties one object to another. For example, a pod is bound to a node by a scheduler.",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"target": "The target object that you want to bind to the standard object.",
}
@ -81,12 +81,12 @@ func (Capabilities) SwaggerDoc() map[string]string {
var map_CephFSVolumeSource = map[string]string{
"": "Represents a Ceph Filesystem mount that lasts the lifetime of a pod Cephfs volumes do not support ownership management or SELinux relabeling.",
"monitors": "Required: Monitors is a collection of Ceph monitors More info: http://releases.k8s.io/HEAD/examples/cephfs/README.md#how-to-use-it",
"monitors": "Required: Monitors is a collection of Ceph monitors More info: http://releases.k8s.io/release-1.2/examples/cephfs/README.md#how-to-use-it",
"path": "Optional: Used as the mounted root, rather than the full Ceph tree, default is /",
"user": "Optional: User is the rados user name, default is admin More info: http://releases.k8s.io/HEAD/examples/cephfs/README.md#how-to-use-it",
"secretFile": "Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: http://releases.k8s.io/HEAD/examples/cephfs/README.md#how-to-use-it",
"secretRef": "Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: http://releases.k8s.io/HEAD/examples/cephfs/README.md#how-to-use-it",
"readOnly": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: http://releases.k8s.io/HEAD/examples/cephfs/README.md#how-to-use-it",
"user": "Optional: User is the rados user name, default is admin More info: http://releases.k8s.io/release-1.2/examples/cephfs/README.md#how-to-use-it",
"secretFile": "Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: http://releases.k8s.io/release-1.2/examples/cephfs/README.md#how-to-use-it",
"secretRef": "Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: http://releases.k8s.io/release-1.2/examples/cephfs/README.md#how-to-use-it",
"readOnly": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: http://releases.k8s.io/release-1.2/examples/cephfs/README.md#how-to-use-it",
}
func (CephFSVolumeSource) SwaggerDoc() map[string]string {
@ -95,9 +95,9 @@ func (CephFSVolumeSource) SwaggerDoc() map[string]string {
var map_CinderVolumeSource = map[string]string{
"": "Represents a cinder volume resource in Openstack. A Cinder volume must exist before mounting to a container. The volume must also be in the same region as the kubelet. Cinder volumes support ownership management and SELinux relabeling.",
"volumeID": "volume id used to identify the volume in cinder More info: http://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md",
"fsType": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md",
"readOnly": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: http://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md",
"volumeID": "volume id used to identify the volume in cinder More info: http://releases.k8s.io/release-1.2/examples/mysql-cinder-pd/README.md",
"fsType": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/release-1.2/examples/mysql-cinder-pd/README.md",
"readOnly": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: http://releases.k8s.io/release-1.2/examples/mysql-cinder-pd/README.md",
}
func (CinderVolumeSource) SwaggerDoc() map[string]string {
@ -118,7 +118,7 @@ func (ComponentCondition) SwaggerDoc() map[string]string {
var map_ComponentStatus = map[string]string{
"": "ComponentStatus (and ComponentStatusList) holds the cluster validation info.",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"conditions": "List of component conditions observed",
}
@ -128,7 +128,7 @@ func (ComponentStatus) SwaggerDoc() map[string]string {
var map_ComponentStatusList = map[string]string{
"": "Status of all the conditions for the component as a list of ComponentStatus objects.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "List of ComponentStatus objects.",
}
@ -138,7 +138,7 @@ func (ComponentStatusList) SwaggerDoc() map[string]string {
var map_ConfigMap = map[string]string{
"": "ConfigMap holds configuration data for pods to consume.",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"data": "Data contains the configuration data. Each key must be a valid DNS_SUBDOMAIN with an optional leading dot.",
}
@ -157,7 +157,7 @@ func (ConfigMapKeySelector) SwaggerDoc() map[string]string {
var map_ConfigMapList = map[string]string{
"": "ConfigMapList is a resource containing a list of ConfigMap objects.",
"metadata": "More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"metadata": "More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"items": "Items is the list of ConfigMaps.",
}
@ -177,20 +177,20 @@ func (ConfigMapVolumeSource) SwaggerDoc() map[string]string {
var map_Container = map[string]string{
"": "A single application container that you want to run within a pod.",
"name": "Name of the container specified as a DNS_LABEL. Each container in a pod must have a unique name (DNS_LABEL). Cannot be updated.",
"image": "Docker image name. More info: http://releases.k8s.io/HEAD/docs/user-guide/images.md",
"command": "Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/containers.md#containers-and-commands",
"args": "Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/containers.md#containers-and-commands",
"image": "Docker image name. More info: http://releases.k8s.io/release-1.2/docs/user-guide/images.md",
"command": "Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: http://releases.k8s.io/release-1.2/docs/user-guide/containers.md#containers-and-commands",
"args": "Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container's environment. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: http://releases.k8s.io/release-1.2/docs/user-guide/containers.md#containers-and-commands",
"workingDir": "Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated.",
"ports": "List of ports to expose from the container. Exposing a port here gives the system additional information about the network connections a container uses, but is primarily informational. Not specifying a port here DOES NOT prevent that port from being exposed. Any port which is listening on the default \"0.0.0.0\" address inside a container will be accessible from the network. Cannot be updated.",
"env": "List of environment variables to set in the container. Cannot be updated.",
"resources": "Compute Resources required by this container. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#resources",
"resources": "Compute Resources required by this container. Cannot be updated. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#resources",
"volumeMounts": "Pod volumes to mount into the container's filesyste. Cannot be updated.",
"livenessProbe": "Periodic probe of container liveness. Container will be restarted if the probe fails. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#container-probes",
"readinessProbe": "Periodic probe of container service readiness. Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#container-probes",
"livenessProbe": "Periodic probe of container liveness. Container will be restarted if the probe fails. Cannot be updated. More info: http://releases.k8s.io/release-1.2/docs/user-guide/pod-states.md#container-probes",
"readinessProbe": "Periodic probe of container service readiness. Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: http://releases.k8s.io/release-1.2/docs/user-guide/pod-states.md#container-probes",
"lifecycle": "Actions that the management system should take in response to container lifecycle events. Cannot be updated.",
"terminationMessagePath": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated.",
"imagePullPolicy": "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/images.md#updating-images",
"securityContext": "Security options the pod should run with. More info: http://releases.k8s.io/HEAD/docs/design/security_context.md",
"imagePullPolicy": "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: http://releases.k8s.io/release-1.2/docs/user-guide/images.md#updating-images",
"securityContext": "Security options the pod should run with. More info: http://releases.k8s.io/release-1.2/docs/design/security_context.md",
"stdin": "Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false.",
"stdinOnce": "Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false",
"tty": "Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. Default is false.",
@ -275,9 +275,9 @@ var map_ContainerStatus = map[string]string{
"lastState": "Details about the container's last termination condition.",
"ready": "Specifies whether the container has passed its readiness probe.",
"restartCount": "The number of times the container has been restarted, currently based on the number of dead containers that have not yet been removed. Note that this is calculated from dead containers. But those containers are subject to garbage collection. This value will get capped at 5 by GC.",
"image": "The image the container is running. More info: http://releases.k8s.io/HEAD/docs/user-guide/images.md",
"image": "The image the container is running. More info: http://releases.k8s.io/release-1.2/docs/user-guide/images.md",
"imageID": "ImageID of the container's image.",
"containerID": "Container's ID in the format 'docker://<container_id>'. More info: http://releases.k8s.io/HEAD/docs/user-guide/container-environment.md#container-information",
"containerID": "Container's ID in the format 'docker://<container_id>'. More info: http://releases.k8s.io/release-1.2/docs/user-guide/container-environment.md#container-information",
}
func (ContainerStatus) SwaggerDoc() map[string]string {
@ -323,7 +323,7 @@ func (DownwardAPIVolumeSource) SwaggerDoc() map[string]string {
var map_EmptyDirVolumeSource = map[string]string{
"": "Represents an empty directory for a pod. Empty directory volumes support ownership management and SELinux relabeling.",
"medium": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#emptydir",
"medium": "What type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#emptydir",
}
func (EmptyDirVolumeSource) SwaggerDoc() map[string]string {
@ -364,7 +364,7 @@ func (EndpointSubset) SwaggerDoc() map[string]string {
var map_Endpoints = map[string]string{
"": "Endpoints is a collection of endpoints that implement the actual service. Example:\n Name: \"mysvc\",\n Subsets: [\n {\n Addresses: [{\"ip\": \"10.10.1.1\"}, {\"ip\": \"10.10.2.2\"}],\n Ports: [{\"name\": \"a\", \"port\": 8675}, {\"name\": \"b\", \"port\": 309}]\n },\n {\n Addresses: [{\"ip\": \"10.10.3.3\"}],\n Ports: [{\"name\": \"a\", \"port\": 93}, {\"name\": \"b\", \"port\": 76}]\n },\n ]",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"subsets": "The set of all endpoints is the union of all subsets. Addresses are placed into subsets according to the IPs they share. A single address with multiple ports, some of which are ready and some of which are not (because they come from different containers) will result in the address being displayed in different subsets for the different ports. No address will appear in both Addresses and NotReadyAddresses in the same subset. Sets of addresses and ports that comprise a service.",
}
@ -374,7 +374,7 @@ func (Endpoints) SwaggerDoc() map[string]string {
var map_EndpointsList = map[string]string{
"": "EndpointsList is a list of endpoints.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "List of endpoints.",
}
@ -406,7 +406,7 @@ func (EnvVarSource) SwaggerDoc() map[string]string {
var map_Event = map[string]string{
"": "Event is a report of an event somewhere in the cluster.",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"involvedObject": "The object that this event is about.",
"reason": "This should be a short, machine understandable string that gives the reason for the transition into the object's current status.",
"message": "A human-readable description of the status of this operation.",
@ -423,7 +423,7 @@ func (Event) SwaggerDoc() map[string]string {
var map_EventList = map[string]string{
"": "EventList is a list of events.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "List of events",
}
@ -495,11 +495,11 @@ func (FlockerVolumeSource) SwaggerDoc() map[string]string {
}
var map_GCEPersistentDiskVolumeSource = map[string]string{
"": "Represents a Persistent Disk resource in Google Compute Engine.\n\nA GCE PD must exist and be formatted before mounting to a container. The disk must also be in the same GCE project and zone as the kubelet. A GCE PD can only be mounted as read/write once. GCE PDs support ownership management and SELinux relabeling.",
"pdName": "Unique name of the PD resource in GCE. Used to identify the disk in GCE. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#gcepersistentdisk",
"fsType": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#gcepersistentdisk",
"partition": "The partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as \"1\". Similarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty). More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#gcepersistentdisk",
"readOnly": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#gcepersistentdisk",
"": "Represents a Persistent Disk resource in Google Compute Engine.\n\nA GCE PD must exist before mounting to a container. The disk must also be in the same GCE project and zone as the kubelet. A GCE PD can only be mounted as read/write once or read-only many times. GCE PDs support ownership management and SELinux relabeling.",
"pdName": "Unique name of the PD resource in GCE. Used to identify the disk in GCE. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#gcepersistentdisk",
"fsType": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#gcepersistentdisk",
"partition": "The partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as \"1\". Similarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty). More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#gcepersistentdisk",
"readOnly": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#gcepersistentdisk",
}
func (GCEPersistentDiskVolumeSource) SwaggerDoc() map[string]string {
@ -519,9 +519,9 @@ func (GitRepoVolumeSource) SwaggerDoc() map[string]string {
var map_GlusterfsVolumeSource = map[string]string{
"": "Represents a Glusterfs mount that lasts the lifetime of a pod. Glusterfs volumes do not support ownership management or SELinux relabeling.",
"endpoints": "EndpointsName is the endpoint name that details Glusterfs topology. More info: http://releases.k8s.io/HEAD/examples/glusterfs/README.md#create-a-pod",
"path": "Path is the Glusterfs volume path. More info: http://releases.k8s.io/HEAD/examples/glusterfs/README.md#create-a-pod",
"readOnly": "ReadOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: http://releases.k8s.io/HEAD/examples/glusterfs/README.md#create-a-pod",
"endpoints": "EndpointsName is the endpoint name that details Glusterfs topology. More info: http://releases.k8s.io/release-1.2/examples/glusterfs/README.md#create-a-pod",
"path": "Path is the Glusterfs volume path. More info: http://releases.k8s.io/release-1.2/examples/glusterfs/README.md#create-a-pod",
"readOnly": "ReadOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: http://releases.k8s.io/release-1.2/examples/glusterfs/README.md#create-a-pod",
}
func (GlusterfsVolumeSource) SwaggerDoc() map[string]string {
@ -564,7 +564,7 @@ func (Handler) SwaggerDoc() map[string]string {
var map_HostPathVolumeSource = map[string]string{
"": "Represents a host path mapped into a pod. Host path volumes do not support ownership management or SELinux relabeling.",
"path": "Path of the directory on the host. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#hostpath",
"path": "Path of the directory on the host. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#hostpath",
}
func (HostPathVolumeSource) SwaggerDoc() map[string]string {
@ -577,7 +577,7 @@ var map_ISCSIVolumeSource = map[string]string{
"iqn": "Target iSCSI Qualified Name.",
"lun": "iSCSI target lun number.",
"iscsiInterface": "Optional: Defaults to 'default' (tcp). iSCSI interface name that uses an iSCSI transport.",
"fsType": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#iscsi",
"fsType": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#iscsi",
"readOnly": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false.",
}
@ -597,8 +597,8 @@ func (KeyToPath) SwaggerDoc() map[string]string {
var map_Lifecycle = map[string]string{
"": "Lifecycle describes actions that the management system should take in response to container lifecycle events. For the PostStart and PreStop lifecycle handlers, management of the container blocks until the action is complete, unless the container process fails, in which case the handler is aborted.",
"postStart": "PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: http://releases.k8s.io/HEAD/docs/user-guide/container-environment.md#hook-details",
"preStop": "PreStop is called immediately before a container is terminated. The container is terminated after the handler completes. The reason for termination is passed to the handler. Regardless of the outcome of the handler, the container is eventually terminated. Other management of the container blocks until the hook completes. More info: http://releases.k8s.io/HEAD/docs/user-guide/container-environment.md#hook-details",
"postStart": "PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: http://releases.k8s.io/release-1.2/docs/user-guide/container-environment.md#hook-details",
"preStop": "PreStop is called immediately before a container is terminated. The container is terminated after the handler completes. The reason for termination is passed to the handler. Regardless of the outcome of the handler, the container is eventually terminated. Other management of the container blocks until the hook completes. More info: http://releases.k8s.io/release-1.2/docs/user-guide/container-environment.md#hook-details",
}
func (Lifecycle) SwaggerDoc() map[string]string {
@ -607,8 +607,8 @@ func (Lifecycle) SwaggerDoc() map[string]string {
var map_LimitRange = map[string]string{
"": "LimitRange sets resource usage limits for each kind of resource in a Namespace.",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the limits enforced. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the limits enforced. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
}
func (LimitRange) SwaggerDoc() map[string]string {
@ -631,8 +631,8 @@ func (LimitRangeItem) SwaggerDoc() map[string]string {
var map_LimitRangeList = map[string]string{
"": "LimitRangeList is a list of LimitRange items.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"items": "Items is a list of LimitRange objects. More info: http://releases.k8s.io/HEAD/docs/design/admission_control_limit_range.md",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "Items is a list of LimitRange objects. More info: http://releases.k8s.io/release-1.2/docs/design/admission_control_limit_range.md",
}
func (LimitRangeList) SwaggerDoc() map[string]string {
@ -650,7 +650,7 @@ func (LimitRangeSpec) SwaggerDoc() map[string]string {
var map_List = map[string]string{
"": "List holds a list of objects, which may not be known by the server.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "List of objects",
}
@ -692,7 +692,7 @@ func (LoadBalancerStatus) SwaggerDoc() map[string]string {
var map_LocalObjectReference = map[string]string{
"": "LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace.",
"name": "Name of the referent. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names",
"name": "Name of the referent. More info: http://releases.k8s.io/release-1.2/docs/user-guide/identifiers.md#names",
}
func (LocalObjectReference) SwaggerDoc() map[string]string {
@ -701,9 +701,9 @@ func (LocalObjectReference) SwaggerDoc() map[string]string {
var map_NFSVolumeSource = map[string]string{
"": "Represents an NFS mount that lasts the lifetime of a pod. NFS volumes do not support ownership management or SELinux relabeling.",
"server": "Server is the hostname or IP address of the NFS server. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#nfs",
"path": "Path that is exported by the NFS server. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#nfs",
"readOnly": "ReadOnly here will force the NFS export to be mounted with read-only permissions. Defaults to false. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#nfs",
"server": "Server is the hostname or IP address of the NFS server. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#nfs",
"path": "Path that is exported by the NFS server. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#nfs",
"readOnly": "ReadOnly here will force the NFS export to be mounted with read-only permissions. Defaults to false. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#nfs",
}
func (NFSVolumeSource) SwaggerDoc() map[string]string {
@ -712,9 +712,9 @@ func (NFSVolumeSource) SwaggerDoc() map[string]string {
var map_Namespace = map[string]string{
"": "Namespace provides a scope for Names. Use of multiple namespaces is optional.",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the behavior of the Namespace. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"status": "Status describes the current status of a Namespace. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the behavior of the Namespace. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
"status": "Status describes the current status of a Namespace. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
}
func (Namespace) SwaggerDoc() map[string]string {
@ -723,8 +723,8 @@ func (Namespace) SwaggerDoc() map[string]string {
var map_NamespaceList = map[string]string{
"": "NamespaceList is a list of Namespaces.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"items": "Items is the list of Namespace objects in the list. More info: http://releases.k8s.io/HEAD/docs/user-guide/namespaces.md",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "Items is the list of Namespace objects in the list. More info: http://releases.k8s.io/release-1.2/docs/user-guide/namespaces.md",
}
func (NamespaceList) SwaggerDoc() map[string]string {
@ -733,7 +733,7 @@ func (NamespaceList) SwaggerDoc() map[string]string {
var map_NamespaceSpec = map[string]string{
"": "NamespaceSpec describes the attributes on a Namespace.",
"finalizers": "Finalizers is an opaque list of values that must be empty to permanently remove object from storage. More info: http://releases.k8s.io/HEAD/docs/design/namespaces.md#finalizers",
"finalizers": "Finalizers is an opaque list of values that must be empty to permanently remove object from storage. More info: http://releases.k8s.io/release-1.2/docs/design/namespaces.md#finalizers",
}
func (NamespaceSpec) SwaggerDoc() map[string]string {
@ -742,7 +742,7 @@ func (NamespaceSpec) SwaggerDoc() map[string]string {
var map_NamespaceStatus = map[string]string{
"": "NamespaceStatus is information about the current status of a Namespace.",
"phase": "Phase is the current lifecycle phase of the namespace. More info: http://releases.k8s.io/HEAD/docs/design/namespaces.md#phases",
"phase": "Phase is the current lifecycle phase of the namespace. More info: http://releases.k8s.io/release-1.2/docs/design/namespaces.md#phases",
}
func (NamespaceStatus) SwaggerDoc() map[string]string {
@ -751,9 +751,9 @@ func (NamespaceStatus) SwaggerDoc() map[string]string {
var map_Node = map[string]string{
"": "Node is a worker node in Kubernetes, formerly known as minion. Each node will have a unique identifier in the cache (i.e. in etcd).",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the behavior of a node. http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"status": "Most recently observed status of the node. Populated by the system. Read-only. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the behavior of a node. http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
"status": "Most recently observed status of the node. Populated by the system. Read-only. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
}
func (Node) SwaggerDoc() map[string]string {
@ -805,7 +805,7 @@ func (NodeDaemonEndpoints) SwaggerDoc() map[string]string {
var map_NodeList = map[string]string{
"": "NodeList is the whole list of all Nodes which have been registered with master.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "List of nodes",
}
@ -856,7 +856,7 @@ var map_NodeSpec = map[string]string{
"podCIDR": "PodCIDR represents the pod IP range assigned to the node.",
"externalID": "External ID of the node assigned by some machine database (e.g. a cloud provider). Deprecated.",
"providerID": "ID of the node assigned by the cloud provider in the format: <ProviderName>://<ProviderSpecificNodeID>",
"unschedulable": "Unschedulable controls node schedulability of new pods. By default, node is schedulable. More info: http://releases.k8s.io/HEAD/docs/admin/node.md#manual-node-administration\"`",
"unschedulable": "Unschedulable controls node schedulability of new pods. By default, node is schedulable. More info: http://releases.k8s.io/release-1.2/docs/admin/node.md#manual-node-administration\"`",
}
func (NodeSpec) SwaggerDoc() map[string]string {
@ -865,13 +865,13 @@ func (NodeSpec) SwaggerDoc() map[string]string {
var map_NodeStatus = map[string]string{
"": "NodeStatus is information about the current status of a node.",
"capacity": "Capacity represents the total resources of a node. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#capacity for more details.",
"capacity": "Capacity represents the total resources of a node. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#capacity for more details.",
"allocatable": "Allocatable represents the resources of a node that are available for scheduling. Defaults to Capacity.",
"phase": "NodePhase is the recently observed lifecycle phase of the node. More info: http://releases.k8s.io/HEAD/docs/admin/node.md#node-phase",
"conditions": "Conditions is an array of current observed node conditions. More info: http://releases.k8s.io/HEAD/docs/admin/node.md#node-condition",
"addresses": "List of addresses reachable to the node. Queried from cloud provider, if available. More info: http://releases.k8s.io/HEAD/docs/admin/node.md#node-addresses",
"phase": "NodePhase is the recently observed lifecycle phase of the node. More info: http://releases.k8s.io/release-1.2/docs/admin/node.md#node-phase",
"conditions": "Conditions is an array of current observed node conditions. More info: http://releases.k8s.io/release-1.2/docs/admin/node.md#node-condition",
"addresses": "List of addresses reachable to the node. Queried from cloud provider, if available. More info: http://releases.k8s.io/release-1.2/docs/admin/node.md#node-addresses",
"daemonEndpoints": "Endpoints of daemons running on the Node.",
"nodeInfo": "Set of ids/uuids to uniquely identify the node. More info: http://releases.k8s.io/HEAD/docs/admin/node.md#node-info",
"nodeInfo": "Set of ids/uuids to uniquely identify the node. More info: http://releases.k8s.io/release-1.2/docs/admin/node.md#node-info",
"images": "List of container images on this node",
}
@ -907,18 +907,18 @@ func (ObjectFieldSelector) SwaggerDoc() map[string]string {
var map_ObjectMeta = map[string]string{
"": "ObjectMeta is metadata that all persisted resources must have, which includes all objects users must create.",
"name": "Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names",
"generateName": "GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server.\n\nIf this field is specified and the generated name exists, the server will NOT return a 409 - instead, it will either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header).\n\nApplied only if Name is not specified. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#idempotency",
"namespace": "Namespace defines the space within each name must be unique. An empty namespace is equivalent to the \"default\" namespace, but \"default\" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty.\n\nMust be a DNS_LABEL. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/namespaces.md",
"name": "Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: http://releases.k8s.io/release-1.2/docs/user-guide/identifiers.md#names",
"generateName": "GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server.\n\nIf this field is specified and the generated name exists, the server will NOT return a 409 - instead, it will either return 201 Created or 500 with Reason ServerTimeout indicating a unique name could not be found in the time allotted, and the client should retry (optionally after the time indicated in the Retry-After header).\n\nApplied only if Name is not specified. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#idempotency",
"namespace": "Namespace defines the space within each name must be unique. An empty namespace is equivalent to the \"default\" namespace, but \"default\" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty.\n\nMust be a DNS_LABEL. Cannot be updated. More info: http://releases.k8s.io/release-1.2/docs/user-guide/namespaces.md",
"selfLink": "SelfLink is a URL representing this object. Populated by the system. Read-only.",
"uid": "UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations.\n\nPopulated by the system. Read-only. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#uids",
"resourceVersion": "An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources.\n\nPopulated by the system. Read-only. Value must be treated as opaque by clients and . More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#concurrency-control-and-consistency",
"generation": "A sequence number representing a specific generation of the desired state. Currently only implemented by replication controllers. Populated by the system. Read-only.",
"creationTimestamp": "CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system. Read-only. Null for lists. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"deletionTimestamp": "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource will be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field. Once set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. Once the resource is deleted in the API, the Kubelet will send a hard termination signal to the container. If not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested. Read-only. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"uid": "UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations.\n\nPopulated by the system. Read-only. More info: http://releases.k8s.io/release-1.2/docs/user-guide/identifiers.md#uids",
"resourceVersion": "An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources.\n\nPopulated by the system. Read-only. Value must be treated as opaque by clients and . More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#concurrency-control-and-consistency",
"generation": "A sequence number representing a specific generation of the desired state. Populated by the system. Read-only.",
"creationTimestamp": "CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system. Read-only. Null for lists. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"deletionTimestamp": "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource will be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field. Once set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. Once the resource is deleted in the API, the Kubelet will send a hard termination signal to the container. If not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested. Read-only. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"deletionGracePeriodSeconds": "Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. Only set when deletionTimestamp is also set. May only be shortened. Read-only.",
"labels": "Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md",
"annotations": "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: http://releases.k8s.io/HEAD/docs/user-guide/annotations.md",
"labels": "Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: http://releases.k8s.io/release-1.2/docs/user-guide/labels.md",
"annotations": "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: http://releases.k8s.io/release-1.2/docs/user-guide/annotations.md",
}
func (ObjectMeta) SwaggerDoc() map[string]string {
@ -927,12 +927,12 @@ func (ObjectMeta) SwaggerDoc() map[string]string {
var map_ObjectReference = map[string]string{
"": "ObjectReference contains enough information to let you inspect or modify the referred object.",
"kind": "Kind of the referent. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"namespace": "Namespace of the referent. More info: http://releases.k8s.io/HEAD/docs/user-guide/namespaces.md",
"name": "Name of the referent. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names",
"uid": "UID of the referent. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#uids",
"kind": "Kind of the referent. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"namespace": "Namespace of the referent. More info: http://releases.k8s.io/release-1.2/docs/user-guide/namespaces.md",
"name": "Name of the referent. More info: http://releases.k8s.io/release-1.2/docs/user-guide/identifiers.md#names",
"uid": "UID of the referent. More info: http://releases.k8s.io/release-1.2/docs/user-guide/identifiers.md#uids",
"apiVersion": "API version of the referent.",
"resourceVersion": "Specific resourceVersion to which this reference is made, if any. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#concurrency-control-and-consistency",
"resourceVersion": "Specific resourceVersion to which this reference is made, if any. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#concurrency-control-and-consistency",
"fieldPath": "If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: \"spec.containers{name}\" (where \"name\" refers to the name of the container that triggered the event) or if no container name is specified \"spec.containers[2]\" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object.",
}
@ -941,10 +941,10 @@ func (ObjectReference) SwaggerDoc() map[string]string {
}
var map_PersistentVolume = map[string]string{
"": "PersistentVolume (PV) is a storage resource provisioned by an administrator. It is analogous to a node. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines a specification of a persistent volume owned by the cluster. Provisioned by an administrator. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#persistent-volumes",
"status": "Status represents the current information/status for the persistent volume. Populated by the system. Read-only. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#persistent-volumes",
"": "PersistentVolume (PV) is a storage resource provisioned by an administrator. It is analogous to a node. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines a specification of a persistent volume owned by the cluster. Provisioned by an administrator. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#persistent-volumes",
"status": "Status represents the current information/status for the persistent volume. Populated by the system. Read-only. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#persistent-volumes",
}
func (PersistentVolume) SwaggerDoc() map[string]string {
@ -953,9 +953,9 @@ func (PersistentVolume) SwaggerDoc() map[string]string {
var map_PersistentVolumeClaim = map[string]string{
"": "PersistentVolumeClaim is a user's request for and claim to a persistent volume",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the desired characteristics of a volume requested by a pod author. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#persistentvolumeclaims",
"status": "Status represents the current information/status of a persistent volume claim. Read-only. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#persistentvolumeclaims",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the desired characteristics of a volume requested by a pod author. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#persistentvolumeclaims",
"status": "Status represents the current information/status of a persistent volume claim. Read-only. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#persistentvolumeclaims",
}
func (PersistentVolumeClaim) SwaggerDoc() map[string]string {
@ -964,8 +964,8 @@ func (PersistentVolumeClaim) SwaggerDoc() map[string]string {
var map_PersistentVolumeClaimList = map[string]string{
"": "PersistentVolumeClaimList is a list of PersistentVolumeClaim items.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"items": "A list of persistent volume claims. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#persistentvolumeclaims",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "A list of persistent volume claims. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#persistentvolumeclaims",
}
func (PersistentVolumeClaimList) SwaggerDoc() map[string]string {
@ -974,8 +974,8 @@ func (PersistentVolumeClaimList) SwaggerDoc() map[string]string {
var map_PersistentVolumeClaimSpec = map[string]string{
"": "PersistentVolumeClaimSpec describes the common attributes of storage devices and allows a Source for provider-specific attributes",
"accessModes": "AccessModes contains the desired access modes the volume should have. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#access-modes-1",
"resources": "Resources represents the minimum resources the volume should have. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#resources",
"accessModes": "AccessModes contains the desired access modes the volume should have. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#access-modes-1",
"resources": "Resources represents the minimum resources the volume should have. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#resources",
"volumeName": "VolumeName is the binding reference to the PersistentVolume backing this claim.",
}
@ -986,7 +986,7 @@ func (PersistentVolumeClaimSpec) SwaggerDoc() map[string]string {
var map_PersistentVolumeClaimStatus = map[string]string{
"": "PersistentVolumeClaimStatus is the current status of a persistent volume claim.",
"phase": "Phase represents the current phase of PersistentVolumeClaim.",
"accessModes": "AccessModes contains the actual access modes the volume backing the PVC has. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#access-modes-1",
"accessModes": "AccessModes contains the actual access modes the volume backing the PVC has. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#access-modes-1",
"capacity": "Represents the actual resources of the underlying volume.",
}
@ -996,7 +996,7 @@ func (PersistentVolumeClaimStatus) SwaggerDoc() map[string]string {
var map_PersistentVolumeClaimVolumeSource = map[string]string{
"": "PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace. This volume finds the bound PV and mounts that volume for the pod. A PersistentVolumeClaimVolumeSource is, essentially, a wrapper around another type of volume that is owned by someone else (the system).",
"claimName": "ClaimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#persistentvolumeclaims",
"claimName": "ClaimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#persistentvolumeclaims",
"readOnly": "Will force the ReadOnly setting in VolumeMounts. Default false.",
}
@ -1006,8 +1006,8 @@ func (PersistentVolumeClaimVolumeSource) SwaggerDoc() map[string]string {
var map_PersistentVolumeList = map[string]string{
"": "PersistentVolumeList is a list of PersistentVolume items.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"items": "List of persistent volumes. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "List of persistent volumes. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md",
}
func (PersistentVolumeList) SwaggerDoc() map[string]string {
@ -1016,14 +1016,14 @@ func (PersistentVolumeList) SwaggerDoc() map[string]string {
var map_PersistentVolumeSource = map[string]string{
"": "PersistentVolumeSource is similar to VolumeSource but meant for the administrator who creates PVs. Exactly one of its members must be set.",
"gcePersistentDisk": "GCEPersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Provisioned by an admin. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#gcepersistentdisk",
"awsElasticBlockStore": "AWSElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#awselasticblockstore",
"hostPath": "HostPath represents a directory on the host. Provisioned by a developer or tester. This is useful for single-node development and testing only! On-host storage is not supported in any way and WILL NOT WORK in a multi-node cluster. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#hostpath",
"glusterfs": "Glusterfs represents a Glusterfs volume that is attached to a host and exposed to the pod. Provisioned by an admin. More info: http://releases.k8s.io/HEAD/examples/glusterfs/README.md",
"nfs": "NFS represents an NFS mount on the host. Provisioned by an admin. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#nfs",
"rbd": "RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md",
"gcePersistentDisk": "GCEPersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Provisioned by an admin. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#gcepersistentdisk",
"awsElasticBlockStore": "AWSElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#awselasticblockstore",
"hostPath": "HostPath represents a directory on the host. Provisioned by a developer or tester. This is useful for single-node development and testing only! On-host storage is not supported in any way and WILL NOT WORK in a multi-node cluster. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#hostpath",
"glusterfs": "Glusterfs represents a Glusterfs volume that is attached to a host and exposed to the pod. Provisioned by an admin. More info: http://releases.k8s.io/release-1.2/examples/glusterfs/README.md",
"nfs": "NFS represents an NFS mount on the host. Provisioned by an admin. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#nfs",
"rbd": "RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: http://releases.k8s.io/release-1.2/examples/rbd/README.md",
"iscsi": "ISCSI represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. Provisioned by an admin.",
"cinder": "Cinder represents a cinder volume attached and mounted on kubelets host machine More info: http://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md",
"cinder": "Cinder represents a cinder volume attached and mounted on kubelets host machine More info: http://releases.k8s.io/release-1.2/examples/mysql-cinder-pd/README.md",
"cephfs": "CephFS represents a Ceph FS mount on the host that shares a pod's lifetime",
"fc": "FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.",
"flocker": "Flocker represents a Flocker volume attached to a kubelet's host machine and exposed to the pod for its usage. This depends on the Flocker control service being running",
@ -1037,10 +1037,10 @@ func (PersistentVolumeSource) SwaggerDoc() map[string]string {
var map_PersistentVolumeSpec = map[string]string{
"": "PersistentVolumeSpec is the specification of a persistent volume.",
"capacity": "A description of the persistent volume's resources and capacity. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#capacity",
"accessModes": "AccessModes contains all ways the volume can be mounted. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#access-modes",
"claimRef": "ClaimRef is part of a bi-directional binding between PersistentVolume and PersistentVolumeClaim. Expected to be non-nil when bound. claim.VolumeName is the authoritative bind between PV and PVC. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#binding",
"persistentVolumeReclaimPolicy": "What happens to a persistent volume when released from its claim. Valid options are Retain (default) and Recycle. Recyling must be supported by the volume plugin underlying this persistent volume. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#recycling-policy",
"capacity": "A description of the persistent volume's resources and capacity. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#capacity",
"accessModes": "AccessModes contains all ways the volume can be mounted. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#access-modes",
"claimRef": "ClaimRef is part of a bi-directional binding between PersistentVolume and PersistentVolumeClaim. Expected to be non-nil when bound. claim.VolumeName is the authoritative bind between PV and PVC. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#binding",
"persistentVolumeReclaimPolicy": "What happens to a persistent volume when released from its claim. Valid options are Retain (default) and Recycle. Recyling must be supported by the volume plugin underlying this persistent volume. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#recycling-policy",
}
func (PersistentVolumeSpec) SwaggerDoc() map[string]string {
@ -1049,7 +1049,7 @@ func (PersistentVolumeSpec) SwaggerDoc() map[string]string {
var map_PersistentVolumeStatus = map[string]string{
"": "PersistentVolumeStatus is the current status of a persistent volume.",
"phase": "Phase indicates if a volume is available, bound to a claim, or released by a claim. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#phase",
"phase": "Phase indicates if a volume is available, bound to a claim, or released by a claim. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#phase",
"message": "A human-readable message indicating details about why the volume is in this state.",
"reason": "Reason is a brief CamelCase string that describes any failure and is meant for machine parsing and tidy display in the CLI.",
}
@ -1060,9 +1060,9 @@ func (PersistentVolumeStatus) SwaggerDoc() map[string]string {
var map_Pod = map[string]string{
"": "Pod is a collection of containers that can run on a host. This resource is created by clients and scheduled onto hosts.",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"spec": "Specification of the desired behavior of the pod. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"status": "Most recently observed status of the pod. This data may not be up to date. Populated by the system. Read-only. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"spec": "Specification of the desired behavior of the pod. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
"status": "Most recently observed status of the pod. This data may not be up to date. Populated by the system. Read-only. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
}
func (Pod) SwaggerDoc() map[string]string {
@ -1084,8 +1084,8 @@ func (PodAttachOptions) SwaggerDoc() map[string]string {
var map_PodCondition = map[string]string{
"": "PodCondition contains details for the current condition of this pod.",
"type": "Type is the type of the condition. Currently only Ready. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#pod-conditions",
"status": "Status is the status of the condition. Can be True, False, Unknown. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#pod-conditions",
"type": "Type is the type of the condition. Currently only Ready. More info: http://releases.k8s.io/release-1.2/docs/user-guide/pod-states.md#pod-conditions",
"status": "Status is the status of the condition. Can be True, False, Unknown. More info: http://releases.k8s.io/release-1.2/docs/user-guide/pod-states.md#pod-conditions",
"lastProbeTime": "Last time we probed the condition.",
"lastTransitionTime": "Last time the condition transitioned from one status to another.",
"reason": "Unique, one-word, CamelCase reason for the condition's last transition.",
@ -1112,8 +1112,8 @@ func (PodExecOptions) SwaggerDoc() map[string]string {
var map_PodList = map[string]string{
"": "PodList is a list of Pods.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"items": "List of pods. More info: http://releases.k8s.io/HEAD/docs/user-guide/pods.md",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "List of pods. More info: http://releases.k8s.io/release-1.2/docs/user-guide/pods.md",
}
func (PodList) SwaggerDoc() map[string]string {
@ -1160,21 +1160,21 @@ func (PodSecurityContext) SwaggerDoc() map[string]string {
var map_PodSpec = map[string]string{
"": "PodSpec is a description of a pod.",
"volumes": "List of volumes that can be mounted by containers belonging to the pod. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md",
"containers": "List of containers belonging to the pod. Containers cannot currently be added or removed. There must be at least one container in a Pod. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/containers.md",
"restartPolicy": "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#restartpolicy",
"volumes": "List of volumes that can be mounted by containers belonging to the pod. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md",
"containers": "List of containers belonging to the pod. Containers cannot currently be added or removed. There must be at least one container in a Pod. Cannot be updated. More info: http://releases.k8s.io/release-1.2/docs/user-guide/containers.md",
"restartPolicy": "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: http://releases.k8s.io/release-1.2/docs/user-guide/pod-states.md#restartpolicy",
"terminationGracePeriodSeconds": "Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds.",
"activeDeadlineSeconds": "Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer.",
"dnsPolicy": "Set DNS policy for containers within the pod. One of 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\".",
"nodeSelector": "NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: http://releases.k8s.io/HEAD/docs/user-guide/node-selection/README.md",
"serviceAccountName": "ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: http://releases.k8s.io/HEAD/docs/design/service_accounts.md",
"nodeSelector": "NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: http://releases.k8s.io/release-1.2/docs/user-guide/node-selection/README.md",
"serviceAccountName": "ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: http://releases.k8s.io/release-1.2/docs/design/service_accounts.md",
"serviceAccount": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead.",
"nodeName": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.",
"hostNetwork": "Host networking requested for this pod. Use the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false.",
"hostPID": "Use the host's pid namespace. Optional: Default to false.",
"hostIPC": "Use the host's ipc namespace. Optional: Default to false.",
"securityContext": "SecurityContext holds pod-level security attributes and common container settings. Optional: Defaults to empty. See type description for default values of each field.",
"imagePullSecrets": "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. For example, in the case of docker, only DockerConfig type secrets are honored. More info: http://releases.k8s.io/HEAD/docs/user-guide/images.md#specifying-imagepullsecrets-on-a-pod",
"imagePullSecrets": "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. For example, in the case of docker, only DockerConfig type secrets are honored. More info: http://releases.k8s.io/release-1.2/docs/user-guide/images.md#specifying-imagepullsecrets-on-a-pod",
}
func (PodSpec) SwaggerDoc() map[string]string {
@ -1183,14 +1183,14 @@ func (PodSpec) SwaggerDoc() map[string]string {
var map_PodStatus = map[string]string{
"": "PodStatus represents information about the status of a pod. Status may trail the actual state of a system.",
"phase": "Current condition of the pod. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#pod-phase",
"conditions": "Current service state of pod. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#pod-conditions",
"phase": "Current condition of the pod. More info: http://releases.k8s.io/release-1.2/docs/user-guide/pod-states.md#pod-phase",
"conditions": "Current service state of pod. More info: http://releases.k8s.io/release-1.2/docs/user-guide/pod-states.md#pod-conditions",
"message": "A human readable message indicating details about why the pod is in this condition.",
"reason": "A brief CamelCase message indicating details about why the pod is in this state. e.g. 'OutOfDisk'",
"hostIP": "IP address of the host to which the pod is assigned. Empty if not yet scheduled.",
"podIP": "IP address allocated to the pod. Routable at least within the cluster. Empty if not yet allocated.",
"startTime": "RFC 3339 date and time at which the object was acknowledged by the Kubelet. This is before the Kubelet pulled the container image(s) for the pod.",
"containerStatuses": "The list has one entry per container in the manifest. Each entry is currently the output of `docker inspect`. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#container-statuses",
"containerStatuses": "The list has one entry per container in the manifest. Each entry is currently the output of `docker inspect`. More info: http://releases.k8s.io/release-1.2/docs/user-guide/pod-states.md#container-statuses",
}
func (PodStatus) SwaggerDoc() map[string]string {
@ -1199,8 +1199,8 @@ func (PodStatus) SwaggerDoc() map[string]string {
var map_PodStatusResult = map[string]string{
"": "PodStatusResult is a wrapper for PodStatus returned by kubelet that can be encode/decoded",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"status": "Most recently observed status of the pod. This data may not be up to date. Populated by the system. Read-only. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"status": "Most recently observed status of the pod. This data may not be up to date. Populated by the system. Read-only. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
}
func (PodStatusResult) SwaggerDoc() map[string]string {
@ -1209,8 +1209,8 @@ func (PodStatusResult) SwaggerDoc() map[string]string {
var map_PodTemplate = map[string]string{
"": "PodTemplate describes a template for creating copies of a predefined pod.",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"template": "Template defines the pods that will be created from this pod template. http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"template": "Template defines the pods that will be created from this pod template. http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
}
func (PodTemplate) SwaggerDoc() map[string]string {
@ -1219,7 +1219,7 @@ func (PodTemplate) SwaggerDoc() map[string]string {
var map_PodTemplateList = map[string]string{
"": "PodTemplateList is a list of PodTemplates.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "List of pod templates",
}
@ -1229,8 +1229,8 @@ func (PodTemplateList) SwaggerDoc() map[string]string {
var map_PodTemplateSpec = map[string]string{
"": "PodTemplateSpec describes the data a pod should have when created from a template",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"spec": "Specification of the desired behavior of the pod. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"spec": "Specification of the desired behavior of the pod. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
}
func (PodTemplateSpec) SwaggerDoc() map[string]string {
@ -1249,8 +1249,8 @@ func (PreferredSchedulingTerm) SwaggerDoc() map[string]string {
var map_Probe = map[string]string{
"": "Probe describes a health check to be performed against a container to determine whether it is alive or ready to receive traffic.",
"initialDelaySeconds": "Number of seconds after the container has started before liveness probes are initiated. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#container-probes",
"timeoutSeconds": "Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#container-probes",
"initialDelaySeconds": "Number of seconds after the container has started before liveness probes are initiated. More info: http://releases.k8s.io/release-1.2/docs/user-guide/pod-states.md#container-probes",
"timeoutSeconds": "Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: http://releases.k8s.io/release-1.2/docs/user-guide/pod-states.md#container-probes",
"periodSeconds": "How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1.",
"successThreshold": "Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness. Minimum value is 1.",
"failureThreshold": "Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1.",
@ -1262,14 +1262,14 @@ func (Probe) SwaggerDoc() map[string]string {
var map_RBDVolumeSource = map[string]string{
"": "Represents a Rados Block Device mount that lasts the lifetime of a pod. RBD volumes support ownership management and SELinux relabeling.",
"monitors": "A collection of Ceph monitors. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it",
"image": "The rados image name. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it",
"fsType": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#rbd",
"pool": "The rados pool name. Default is rbd. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it.",
"user": "The rados user name. Default is admin. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it",
"keyring": "Keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it",
"secretRef": "SecretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is empty. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it",
"readOnly": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md#how-to-use-it",
"monitors": "A collection of Ceph monitors. More info: http://releases.k8s.io/release-1.2/examples/rbd/README.md#how-to-use-it",
"image": "The rados image name. More info: http://releases.k8s.io/release-1.2/examples/rbd/README.md#how-to-use-it",
"fsType": "Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#rbd",
"pool": "The rados pool name. Default is rbd. More info: http://releases.k8s.io/release-1.2/examples/rbd/README.md#how-to-use-it.",
"user": "The rados user name. Default is admin. More info: http://releases.k8s.io/release-1.2/examples/rbd/README.md#how-to-use-it",
"keyring": "Keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: http://releases.k8s.io/release-1.2/examples/rbd/README.md#how-to-use-it",
"secretRef": "SecretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is empty. More info: http://releases.k8s.io/release-1.2/examples/rbd/README.md#how-to-use-it",
"readOnly": "ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: http://releases.k8s.io/release-1.2/examples/rbd/README.md#how-to-use-it",
}
func (RBDVolumeSource) SwaggerDoc() map[string]string {
@ -1278,7 +1278,7 @@ func (RBDVolumeSource) SwaggerDoc() map[string]string {
var map_RangeAllocation = map[string]string{
"": "RangeAllocation is not a public type.",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"range": "Range is string that identifies the range represented by 'data'.",
"data": "Data is a bit array containing all allocated addresses in the previous segment.",
}
@ -1289,9 +1289,9 @@ func (RangeAllocation) SwaggerDoc() map[string]string {
var map_ReplicationController = map[string]string{
"": "ReplicationController represents the configuration of a replication controller.",
"metadata": "If the Labels of a ReplicationController are empty, they are defaulted to be the same as the Pod(s) that the replication controller manages. Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the specification of the desired behavior of the replication controller. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"status": "Status is the most recently observed status of the replication controller. This data may be out of date by some window of time. Populated by the system. Read-only. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"metadata": "If the Labels of a ReplicationController are empty, they are defaulted to be the same as the Pod(s) that the replication controller manages. Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the specification of the desired behavior of the replication controller. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
"status": "Status is the most recently observed status of the replication controller. This data may be out of date by some window of time. Populated by the system. Read-only. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
}
func (ReplicationController) SwaggerDoc() map[string]string {
@ -1300,8 +1300,8 @@ func (ReplicationController) SwaggerDoc() map[string]string {
var map_ReplicationControllerList = map[string]string{
"": "ReplicationControllerList is a collection of replication controllers.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"items": "List of replication controllers. More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "List of replication controllers. More info: http://releases.k8s.io/release-1.2/docs/user-guide/replication-controller.md",
}
func (ReplicationControllerList) SwaggerDoc() map[string]string {
@ -1310,9 +1310,9 @@ func (ReplicationControllerList) SwaggerDoc() map[string]string {
var map_ReplicationControllerSpec = map[string]string{
"": "ReplicationControllerSpec is the specification of a replication controller.",
"replicas": "Replicas is the number of desired replicas. This is a pointer to distinguish between explicit zero and unspecified. Defaults to 1. More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md#what-is-a-replication-controller",
"selector": "Selector is a label query over pods that should match the Replicas count. If Selector is empty, it is defaulted to the labels present on the Pod template. Label keys and values that must match in order to be controlled by this replication controller, if empty defaulted to labels on Pod template. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors",
"template": "Template is the object that describes the pod that will be created if insufficient replicas are detected. This takes precedence over a TemplateRef. More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md#pod-template",
"replicas": "Replicas is the number of desired replicas. This is a pointer to distinguish between explicit zero and unspecified. Defaults to 1. More info: http://releases.k8s.io/release-1.2/docs/user-guide/replication-controller.md#what-is-a-replication-controller",
"selector": "Selector is a label query over pods that should match the Replicas count. If Selector is empty, it is defaulted to the labels present on the Pod template. Label keys and values that must match in order to be controlled by this replication controller, if empty defaulted to labels on Pod template. More info: http://releases.k8s.io/release-1.2/docs/user-guide/labels.md#label-selectors",
"template": "Template is the object that describes the pod that will be created if insufficient replicas are detected. This takes precedence over a TemplateRef. More info: http://releases.k8s.io/release-1.2/docs/user-guide/replication-controller.md#pod-template",
}
func (ReplicationControllerSpec) SwaggerDoc() map[string]string {
@ -1320,9 +1320,10 @@ func (ReplicationControllerSpec) SwaggerDoc() map[string]string {
}
var map_ReplicationControllerStatus = map[string]string{
"": "ReplicationControllerStatus represents the current status of a replication controller.",
"replicas": "Replicas is the most recently oberved number of replicas. More info: http://releases.k8s.io/HEAD/docs/user-guide/replication-controller.md#what-is-a-replication-controller",
"observedGeneration": "ObservedGeneration reflects the generation of the most recently observed replication controller.",
"": "ReplicationControllerStatus represents the current status of a replication controller.",
"replicas": "Replicas is the most recently oberved number of replicas. More info: http://releases.k8s.io/release-1.2/docs/user-guide/replication-controller.md#what-is-a-replication-controller",
"fullyLabeledReplicas": "The number of pods that have labels matching the labels of the pod template of the replication controller.",
"observedGeneration": "ObservedGeneration reflects the generation of the most recently observed replication controller.",
}
func (ReplicationControllerStatus) SwaggerDoc() map[string]string {
@ -1331,9 +1332,9 @@ func (ReplicationControllerStatus) SwaggerDoc() map[string]string {
var map_ResourceQuota = map[string]string{
"": "ResourceQuota sets aggregate quota restrictions enforced per namespace",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the desired quota. http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"status": "Status defines the actual enforced quota and its current usage. http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the desired quota. http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
"status": "Status defines the actual enforced quota and its current usage. http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
}
func (ResourceQuota) SwaggerDoc() map[string]string {
@ -1342,8 +1343,8 @@ func (ResourceQuota) SwaggerDoc() map[string]string {
var map_ResourceQuotaList = map[string]string{
"": "ResourceQuotaList is a list of ResourceQuota items.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"items": "Items is a list of ResourceQuota objects. More info: http://releases.k8s.io/HEAD/docs/design/admission_control_resource_quota.md#admissioncontrol-plugin-resourcequota",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "Items is a list of ResourceQuota objects. More info: http://releases.k8s.io/release-1.2/docs/design/admission_control_resource_quota.md#admissioncontrol-plugin-resourcequota",
}
func (ResourceQuotaList) SwaggerDoc() map[string]string {
@ -1351,8 +1352,9 @@ func (ResourceQuotaList) SwaggerDoc() map[string]string {
}
var map_ResourceQuotaSpec = map[string]string{
"": "ResourceQuotaSpec defines the desired hard limits to enforce for Quota.",
"hard": "Hard is the set of desired hard limits for each named resource. More info: http://releases.k8s.io/HEAD/docs/design/admission_control_resource_quota.md#admissioncontrol-plugin-resourcequota",
"": "ResourceQuotaSpec defines the desired hard limits to enforce for Quota.",
"hard": "Hard is the set of desired hard limits for each named resource. More info: http://releases.k8s.io/release-1.2/docs/design/admission_control_resource_quota.md#admissioncontrol-plugin-resourcequota",
"scopes": "A collection of filters that must match each object tracked by a quota. If not specified, the quota matches all objects.",
}
func (ResourceQuotaSpec) SwaggerDoc() map[string]string {
@ -1361,7 +1363,7 @@ func (ResourceQuotaSpec) SwaggerDoc() map[string]string {
var map_ResourceQuotaStatus = map[string]string{
"": "ResourceQuotaStatus defines the enforced hard limits and observed use.",
"hard": "Hard is the set of enforced hard limits for each named resource. More info: http://releases.k8s.io/HEAD/docs/design/admission_control_resource_quota.md#admissioncontrol-plugin-resourcequota",
"hard": "Hard is the set of enforced hard limits for each named resource. More info: http://releases.k8s.io/release-1.2/docs/design/admission_control_resource_quota.md#admissioncontrol-plugin-resourcequota",
"used": "Used is the current observed total usage of the resource in the namespace.",
}
@ -1371,8 +1373,8 @@ func (ResourceQuotaStatus) SwaggerDoc() map[string]string {
var map_ResourceRequirements = map[string]string{
"": "ResourceRequirements describes the compute resource requirements.",
"limits": "Limits describes the maximum amount of compute resources allowed. More info: http://releases.k8s.io/HEAD/docs/design/resources.md#resource-specifications",
"requests": "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: http://releases.k8s.io/HEAD/docs/design/resources.md#resource-specifications",
"limits": "Limits describes the maximum amount of compute resources allowed. More info: http://releases.k8s.io/release-1.2/docs/design/resources.md#resource-specifications",
"requests": "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: http://releases.k8s.io/release-1.2/docs/design/resources.md#resource-specifications",
}
func (ResourceRequirements) SwaggerDoc() map[string]string {
@ -1393,7 +1395,7 @@ func (SELinuxOptions) SwaggerDoc() map[string]string {
var map_Secret = map[string]string{
"": "Secret holds secret data of a certain type. The total bytes of the values in the Data field must be less than MaxSecretSize bytes.",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"data": "Data contains the secret data. Each key must be a valid DNS_SUBDOMAIN or leading dot followed by valid DNS_SUBDOMAIN. The serialized form of the secret data is a base64 encoded string, representing the arbitrary (possibly non-string) data value here. Described in https://tools.ietf.org/html/rfc4648#section-4",
"type": "Used to facilitate programmatic handling of secret data.",
}
@ -1413,8 +1415,8 @@ func (SecretKeySelector) SwaggerDoc() map[string]string {
var map_SecretList = map[string]string{
"": "SecretList is a list of Secret.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"items": "Items is a list of secret objects. More info: http://releases.k8s.io/HEAD/docs/user-guide/secrets.md",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "Items is a list of secret objects. More info: http://releases.k8s.io/release-1.2/docs/user-guide/secrets.md",
}
func (SecretList) SwaggerDoc() map[string]string {
@ -1423,7 +1425,7 @@ func (SecretList) SwaggerDoc() map[string]string {
var map_SecretVolumeSource = map[string]string{
"": "Adapts a Secret into a volume.\n\nThe contents of the target Secret's Data field will be presented in a volume as files using the keys in the Data field as the file names. Secret volumes support ownership management and SELinux relabeling.",
"secretName": "Name of the secret in the pod's namespace to use. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#secrets",
"secretName": "Name of the secret in the pod's namespace to use. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#secrets",
}
func (SecretVolumeSource) SwaggerDoc() map[string]string {
@ -1455,9 +1457,9 @@ func (SerializedReference) SwaggerDoc() map[string]string {
var map_Service = map[string]string{
"": "Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy.",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the behavior of a service. http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"status": "Most recently observed status of the service. Populated by the system. Read-only. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"spec": "Spec defines the behavior of a service. http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
"status": "Most recently observed status of the service. Populated by the system. Read-only. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status",
}
func (Service) SwaggerDoc() map[string]string {
@ -1466,9 +1468,9 @@ func (Service) SwaggerDoc() map[string]string {
var map_ServiceAccount = map[string]string{
"": "ServiceAccount binds together: * a name, understood by users, and perhaps by peripheral systems, for an identity * a principal that can be authenticated and authorized * a set of secrets",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"secrets": "Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount. More info: http://releases.k8s.io/HEAD/docs/user-guide/secrets.md",
"imagePullSecrets": "ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. More info: http://releases.k8s.io/HEAD/docs/user-guide/secrets.md#manually-specifying-an-imagepullsecret",
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"secrets": "Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount. More info: http://releases.k8s.io/release-1.2/docs/user-guide/secrets.md",
"imagePullSecrets": "ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. More info: http://releases.k8s.io/release-1.2/docs/user-guide/secrets.md#manually-specifying-an-imagepullsecret",
}
func (ServiceAccount) SwaggerDoc() map[string]string {
@ -1477,8 +1479,8 @@ func (ServiceAccount) SwaggerDoc() map[string]string {
var map_ServiceAccountList = map[string]string{
"": "ServiceAccountList is a list of ServiceAccount objects",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"items": "List of ServiceAccounts. More info: http://releases.k8s.io/HEAD/docs/design/service_accounts.md#service-accounts",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "List of ServiceAccounts. More info: http://releases.k8s.io/release-1.2/docs/design/service_accounts.md#service-accounts",
}
func (ServiceAccountList) SwaggerDoc() map[string]string {
@ -1487,7 +1489,7 @@ func (ServiceAccountList) SwaggerDoc() map[string]string {
var map_ServiceList = map[string]string{
"": "ServiceList holds a list of services.",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds",
"metadata": "Standard list metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds",
"items": "List of services",
}
@ -1500,8 +1502,8 @@ var map_ServicePort = map[string]string{
"name": "The name of this port within the service. This must be a DNS_LABEL. All ports within a ServiceSpec must have unique names. This maps to the 'Name' field in EndpointPort objects. Optional if only one ServicePort is defined on this service.",
"protocol": "The IP protocol for this port. Supports \"TCP\" and \"UDP\". Default is TCP.",
"port": "The port that will be exposed by this service.",
"targetPort": "Number or name of the port to access on the pods targeted by the service. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. If this is a string, it will be looked up as a named port in the target Pod's container ports. If this is not specified, the value of Port is used (an identity map). Defaults to the service port. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#defining-a-service",
"nodePort": "The port on each node on which this service is exposed when type=NodePort or LoadBalancer. Usually assigned by the system. If specified, it will be allocated to the service if unused or else creation of the service will fail. Default is to auto-allocate a port if the ServiceType of this Service requires one. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#type--nodeport",
"targetPort": "Number or name of the port to access on the pods targeted by the service. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. If this is a string, it will be looked up as a named port in the target Pod's container ports. If this is not specified, the value of the 'port' field is used (an identity map). This field is ignored for services with clusterIP=None, and should be omitted or set equal to the 'port' field. More info: http://releases.k8s.io/release-1.2/docs/user-guide/services.md#defining-a-service",
"nodePort": "The port on each node on which this service is exposed when type=NodePort or LoadBalancer. Usually assigned by the system. If specified, it will be allocated to the service if unused or else creation of the service will fail. Default is to auto-allocate a port if the ServiceType of this Service requires one. More info: http://releases.k8s.io/release-1.2/docs/user-guide/services.md#type--nodeport",
}
func (ServicePort) SwaggerDoc() map[string]string {
@ -1519,13 +1521,13 @@ func (ServiceProxyOptions) SwaggerDoc() map[string]string {
var map_ServiceSpec = map[string]string{
"": "ServiceSpec describes the attributes that a user creates on a service.",
"ports": "The list of ports that are exposed by this service. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
"selector": "This service will route traffic to pods having labels matching this selector. Label keys and values that must match in order to receive traffic for this service. If empty, all pods are selected, if not specified, endpoints must be manually specified. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#overview",
"clusterIP": "ClusterIP is usually assigned by the master and is the IP address of the service. If specified, it will be allocated to the service if it is unused or else creation of the service will fail. Valid values are None, empty string (\"\"), or a valid IP address. 'None' can be specified for a headless service when proxying is not required. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
"type": "Type of exposed service. Must be ClusterIP, NodePort, or LoadBalancer. Defaults to ClusterIP. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#external-services",
"ports": "The list of ports that are exposed by this service. More info: http://releases.k8s.io/release-1.2/docs/user-guide/services.md#virtual-ips-and-service-proxies",
"selector": "This service will route traffic to pods having labels matching this selector. Label keys and values that must match in order to receive traffic for this service. If empty, all pods are selected, if not specified, endpoints must be manually specified. More info: http://releases.k8s.io/release-1.2/docs/user-guide/services.md#overview",
"clusterIP": "ClusterIP is usually assigned by the master and is the IP address of the service. If specified, it will be allocated to the service if it is unused or else creation of the service will fail. Valid values are None, empty string (\"\"), or a valid IP address. 'None' can be specified for a headless service when proxying is not required. Cannot be updated. More info: http://releases.k8s.io/release-1.2/docs/user-guide/services.md#virtual-ips-and-service-proxies",
"type": "Type of exposed service. Must be ClusterIP, NodePort, or LoadBalancer. Defaults to ClusterIP. More info: http://releases.k8s.io/release-1.2/docs/user-guide/services.md#external-services",
"externalIPs": "externalIPs is a list of IP addresses for which nodes in the cluster will also accept traffic for this service. These IPs are not managed by Kubernetes. The user is responsible for ensuring that traffic arrives at a node with this IP. A common example is external load-balancers that are not part of the Kubernetes system. A previous form of this functionality exists as the deprecatedPublicIPs field. When using this field, callers should also clear the deprecatedPublicIPs field.",
"deprecatedPublicIPs": "deprecatedPublicIPs is deprecated and replaced by the externalIPs field with almost the exact same semantics. This field is retained in the v1 API for compatibility until at least 8/20/2016. It will be removed from any new API revisions. If both deprecatedPublicIPs *and* externalIPs are set, deprecatedPublicIPs is used.",
"sessionAffinity": "Supports \"ClientIP\" and \"None\". Used to maintain session affinity. Enable client IP based session affinity. Must be ClientIP or None. Defaults to None. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
"sessionAffinity": "Supports \"ClientIP\" and \"None\". Used to maintain session affinity. Enable client IP based session affinity. Must be ClientIP or None. Defaults to None. More info: http://releases.k8s.io/release-1.2/docs/user-guide/services.md#virtual-ips-and-service-proxies",
"loadBalancerIP": "Only applies to Service Type: LoadBalancer LoadBalancer will get created with the IP specified in this field. This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. This field will be ignored if the cloud-provider does not support the feature.",
}
@ -1553,7 +1555,7 @@ func (TCPSocketAction) SwaggerDoc() map[string]string {
var map_Volume = map[string]string{
"": "Volume represents a named volume in a pod that may be accessed by any container in the pod.",
"name": "Volume's name. Must be a DNS_LABEL and unique within the pod. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names",
"name": "Volume's name. Must be a DNS_LABEL and unique within the pod. More info: http://releases.k8s.io/release-1.2/docs/user-guide/identifiers.md#names",
}
func (Volume) SwaggerDoc() map[string]string {
@ -1564,7 +1566,7 @@ var map_VolumeMount = map[string]string{
"": "VolumeMount describes a mounting of a Volume within a container.",
"name": "This must match the Name of a Volume.",
"readOnly": "Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.",
"mountPath": "Path within the container at which the volume should be mounted.",
"mountPath": "Path within the container at which the volume should be mounted. Must not contain ':'.",
}
func (VolumeMount) SwaggerDoc() map[string]string {
@ -1573,19 +1575,19 @@ func (VolumeMount) SwaggerDoc() map[string]string {
var map_VolumeSource = map[string]string{
"": "Represents the source of a volume to mount. Only one of its members may be specified.",
"hostPath": "HostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#hostpath",
"emptyDir": "EmptyDir represents a temporary directory that shares a pod's lifetime. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#emptydir",
"gcePersistentDisk": "GCEPersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#gcepersistentdisk",
"awsElasticBlockStore": "AWSElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#awselasticblockstore",
"hostPath": "HostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#hostpath",
"emptyDir": "EmptyDir represents a temporary directory that shares a pod's lifetime. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#emptydir",
"gcePersistentDisk": "GCEPersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#gcepersistentdisk",
"awsElasticBlockStore": "AWSElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#awselasticblockstore",
"gitRepo": "GitRepo represents a git repository at a particular revision.",
"secret": "Secret represents a secret that should populate this volume. More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#secrets",
"nfs": "NFS represents an NFS mount on the host that shares a pod's lifetime More info: http://releases.k8s.io/HEAD/docs/user-guide/volumes.md#nfs",
"iscsi": "ISCSI represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: http://releases.k8s.io/HEAD/examples/iscsi/README.md",
"glusterfs": "Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. More info: http://releases.k8s.io/HEAD/examples/glusterfs/README.md",
"persistentVolumeClaim": "PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#persistentvolumeclaims",
"rbd": "RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: http://releases.k8s.io/HEAD/examples/rbd/README.md",
"secret": "Secret represents a secret that should populate this volume. More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#secrets",
"nfs": "NFS represents an NFS mount on the host that shares a pod's lifetime More info: http://releases.k8s.io/release-1.2/docs/user-guide/volumes.md#nfs",
"iscsi": "ISCSI represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. More info: http://releases.k8s.io/release-1.2/examples/iscsi/README.md",
"glusterfs": "Glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. More info: http://releases.k8s.io/release-1.2/examples/glusterfs/README.md",
"persistentVolumeClaim": "PersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: http://releases.k8s.io/release-1.2/docs/user-guide/persistent-volumes.md#persistentvolumeclaims",
"rbd": "RBD represents a Rados Block Device mount on the host that shares a pod's lifetime. More info: http://releases.k8s.io/release-1.2/examples/rbd/README.md",
"flexVolume": "FlexVolume represents a generic volume resource that is provisioned/attached using a exec based plugin. This is an alpha feature and may change in future.",
"cinder": "Cinder represents a cinder volume attached and mounted on kubelets host machine More info: http://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md",
"cinder": "Cinder represents a cinder volume attached and mounted on kubelets host machine More info: http://releases.k8s.io/release-1.2/examples/mysql-cinder-pd/README.md",
"cephfs": "CephFS represents a Ceph FS mount on the host that shares a pod's lifetime",
"flocker": "Flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running",
"downwardAPI": "DownwardAPI represents downward API about the pod that should populate this volume",

View file

@ -1,60 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package validation
import (
"testing"
"k8s.io/kubernetes/pkg/api"
)
func TestValidateEvent(t *testing.T) {
table := []struct {
*api.Event
valid bool
}{
{
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test1",
Namespace: "foo",
},
InvolvedObject: api.ObjectReference{
Namespace: "bar",
},
},
false,
}, {
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test1",
Namespace: "aoeu-_-aoeu",
},
InvolvedObject: api.ObjectReference{
Namespace: "aoeu-_-aoeu",
},
},
false,
},
}
for _, item := range table {
if e, a := item.valid, len(ValidateEvent(item.Event)) == 0; e != a {
t.Errorf("%v: expected %v, got %v", item.Event.Name, e, a)
}
}
}

View file

@ -1,149 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package validation
import (
"strings"
"testing"
)
func TestValidatePathSegmentName(t *testing.T) {
testcases := map[string]struct {
Name string
Prefix bool
ExpectedOK bool
ExpectedMsg string
}{
"empty": {
Name: "",
Prefix: false,
ExpectedOK: true,
ExpectedMsg: "",
},
"empty,prefix": {
Name: "",
Prefix: true,
ExpectedOK: true,
ExpectedMsg: "",
},
"valid": {
Name: "foo.bar.baz",
Prefix: false,
ExpectedOK: true,
ExpectedMsg: "",
},
"valid,prefix": {
Name: "foo.bar.baz",
Prefix: true,
ExpectedOK: true,
ExpectedMsg: "",
},
// Make sure mixed case, non DNS subdomain characters are tolerated
"valid complex": {
Name: "sha256:ABCDEF012345@ABCDEF012345",
Prefix: false,
ExpectedOK: true,
ExpectedMsg: "",
},
// Make sure non-ascii characters are tolerated
"valid extended charset": {
Name: "Iñtërnâtiônàlizætiøn",
Prefix: false,
ExpectedOK: true,
ExpectedMsg: "",
},
"dot": {
Name: ".",
Prefix: false,
ExpectedOK: false,
ExpectedMsg: ".",
},
"dot leading": {
Name: ".test",
Prefix: false,
ExpectedOK: true,
ExpectedMsg: "",
},
"dot,prefix": {
Name: ".",
Prefix: true,
ExpectedOK: true, // allowed because a suffix could make it valid
ExpectedMsg: "",
},
"dot dot": {
Name: "..",
Prefix: false,
ExpectedOK: false,
ExpectedMsg: "..",
},
"dot dot leading": {
Name: "..test",
Prefix: false,
ExpectedOK: true,
ExpectedMsg: "",
},
"dot dot,prefix": {
Name: "..",
Prefix: true,
ExpectedOK: true, // allowed because a suffix could make it valid
ExpectedMsg: "",
},
"slash": {
Name: "foo/bar",
Prefix: false,
ExpectedOK: false,
ExpectedMsg: "/",
},
"slash,prefix": {
Name: "foo/bar",
Prefix: true,
ExpectedOK: false,
ExpectedMsg: "/",
},
"percent": {
Name: "foo%bar",
Prefix: false,
ExpectedOK: false,
ExpectedMsg: "%",
},
"percent,prefix": {
Name: "foo%bar",
Prefix: true,
ExpectedOK: false,
ExpectedMsg: "%",
},
}
for k, tc := range testcases {
ok, msg := ValidatePathSegmentName(tc.Name, tc.Prefix)
if ok != tc.ExpectedOK {
t.Errorf("%s: expected ok=%v, got %v", k, tc.ExpectedOK, ok)
}
if len(tc.ExpectedMsg) == 0 && len(msg) > 0 {
t.Errorf("%s: expected no message, got %v", k, msg)
}
if len(tc.ExpectedMsg) > 0 && !strings.Contains(msg, tc.ExpectedMsg) {
t.Errorf("%s: expected message containing %q, got %v", k, tc.ExpectedMsg, msg)
}
}
}

View file

@ -44,6 +44,14 @@ func NewInvalidTypeError(expected reflect.Kind, observed reflect.Kind, fieldName
return &InvalidTypeError{expected, observed, fieldName}
}
// TypeNotFoundError is returned when specified type
// can not found in schema
type TypeNotFoundError string
func (tnfe TypeNotFoundError) Error() string {
return fmt.Sprintf("couldn't find type: %s", string(tnfe))
}
// Schema is an interface that knows how to validate an API object serialized to a byte array.
type Schema interface {
ValidateBytes(data []byte) error
@ -164,7 +172,7 @@ func (s *SwaggerSchema) ValidateObject(obj interface{}, fieldName, typeName stri
models := s.api.Models
model, ok := models.At(typeName)
if !ok {
return append(allErrs, fmt.Errorf("couldn't find type: %s", typeName))
return append(allErrs, TypeNotFoundError(typeName))
}
properties := model.Properties
if len(properties.List) == 0 {

View file

@ -1,156 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package validation
import (
"io/ioutil"
"math/rand"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/runtime"
)
func readPod(filename string) (string, error) {
data, err := ioutil.ReadFile("testdata/" + testapi.Default.GroupVersion().Version + "/" + filename)
if err != nil {
return "", err
}
return string(data), nil
}
func loadSchemaForTest() (Schema, error) {
// TODO this path is broken
pathToSwaggerSpec := "../../../api/swagger-spec/" + testapi.Default.GroupVersion().Version + ".json"
data, err := ioutil.ReadFile(pathToSwaggerSpec)
if err != nil {
return nil, err
}
return NewSwaggerSchemaFromBytes(data)
}
func TestLoad(t *testing.T) {
_, err := loadSchemaForTest()
if err != nil {
t.Errorf("Failed to load: %v", err)
}
}
func TestValidateOk(t *testing.T) {
schema, err := loadSchemaForTest()
if err != nil {
t.Errorf("Failed to load: %v", err)
}
tests := []struct {
obj runtime.Object
typeName string
}{
{obj: &api.Pod{}},
{obj: &api.Service{}},
{obj: &api.ReplicationController{}},
}
seed := rand.Int63()
apiObjectFuzzer := apitesting.FuzzerFor(nil, testapi.Default.InternalGroupVersion(), rand.NewSource(seed))
for i := 0; i < 5; i++ {
for _, test := range tests {
testObj := test.obj
apiObjectFuzzer.Fuzz(testObj)
data, err := runtime.Encode(testapi.Default.Codec(), testObj)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
err = schema.ValidateBytes(data)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
}
}
}
func TestInvalid(t *testing.T) {
schema, err := loadSchemaForTest()
if err != nil {
t.Errorf("Failed to load: %v", err)
}
tests := []string{
"invalidPod1.json", // command is a string, instead of []string.
"invalidPod2.json", // hostPort if of type string, instead of int.
"invalidPod3.json", // volumes is not an array of objects.
"invalidPod.yaml", // command is a string, instead of []string.
}
for _, test := range tests {
pod, err := readPod(test)
if err != nil {
t.Errorf("could not read file: %s", pod)
}
err = schema.ValidateBytes([]byte(pod))
if err == nil {
t.Errorf("unexpected non-error, err: %s for pod: %s", err, pod)
}
}
}
func TestValid(t *testing.T) {
schema, err := loadSchemaForTest()
if err != nil {
t.Errorf("Failed to load: %v", err)
}
tests := []string{
"validPod.yaml",
}
for _, test := range tests {
pod, err := readPod(test)
if err != nil {
t.Errorf("could not read file: %s", test)
}
err = schema.ValidateBytes([]byte(pod))
if err != nil {
t.Errorf("unexpected error %s, for pod %s", err, pod)
}
}
}
func TestVersionRegex(t *testing.T) {
testCases := []struct {
typeName string
match bool
}{
{
typeName: "v1.Binding",
match: true,
},
{
typeName: "v1beta1.Binding",
match: true,
},
{
typeName: "Binding",
match: false,
},
}
for _, test := range testCases {
if versionRegexp.MatchString(test.typeName) && !test.match {
t.Errorf("unexpected error: expect %s not to match the regular expression", test.typeName)
}
if !versionRegexp.MatchString(test.typeName) && test.match {
t.Errorf("unexpected error: expect %s to match the regular expression", test.typeName)
}
}
}

View file

@ -1,11 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
labels:
name: redis-master
name: name
spec:
containers:
- args: "this is a bad command"
image: redis
name: master

View file

@ -1,19 +0,0 @@
{
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "name",
"labels": {
"name": "redis-master"
}
},
"spec": {
"containers": [
{
"name": "master",
"image": "redis",
"args": "this is a bad command"
}
]
}
}

View file

@ -1,35 +0,0 @@
{
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "apache-php",
"labels": {
"name": "apache-php"
}
},
"spec": {
"volumes": [{
"name": "shared-disk"
}],
"containers": [
{
"name": "apache-php",
"image": "php:5.6.2-apache",
"ports": [
{
"name": "apache",
"hostPort": "13380",
"containerPort": 80,
"protocol": "TCP"
}
],
"volumeMounts": [
{
"name": "shared-disk",
"mountPath": "/var/www/html"
}
]
}
]
}
}

View file

@ -1,35 +0,0 @@
{
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "apache-php",
"labels": {
"name": "apache-php"
}
},
"spec": {
"volumes": [
"name": "shared-disk"
],
"containers": [
{
"name": "apache-php",
"image": "php:5.6.2-apache",
"ports": [
{
"name": "apache",
"hostPort": 13380,
"containerPort": 80,
"protocol": "TCP"
}
],
"volumeMounts": [
{
"name": "shared-disk",
"mountPath": "/var/www/html"
}
]
}
]
}
}

View file

@ -1,16 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
labels:
name: redis-master
name: name
spec:
containers:
- args:
- this
- is
- an
- ok
- command
image: redis
name: master

View file

@ -27,16 +27,18 @@ import (
"regexp"
"strings"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/endpoints"
utilpod "k8s.io/kubernetes/pkg/api/pod"
"k8s.io/kubernetes/pkg/api/resource"
apiservice "k8s.io/kubernetes/pkg/api/service"
"k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/util/intstr"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/util/validation"
"k8s.io/kubernetes/pkg/util/validation/field"
"github.com/golang/glog"
)
// TODO: delete this global variable when we enable the validation of common
@ -44,6 +46,7 @@ import (
var RepairMalformedUpdates bool = true
const isNegativeErrorMsg string = `must be greater than or equal to 0`
const isInvalidQuotaResource string = `must be a standard resource for quota`
const fieldImmutableErrorMsg string = `field is immutable`
const cIdentifierErrorMsg string = `must be a C identifier (matching regex ` + validation.CIdentifierFmt + `): e.g. "my_name" or "MyName"`
const isNotIntegerErrorMsg string = `must be an integer`
@ -111,10 +114,34 @@ func ValidateAnnotations(annotations map[string]string, fldPath *field.Path) fie
if totalSize > (int64)(totalAnnotationSizeLimitB) {
allErrs = append(allErrs, field.TooLong(fldPath, "", totalAnnotationSizeLimitB))
}
return allErrs
}
func ValidatePodSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if annotations[api.AffinityAnnotationKey] != "" {
allErrs = append(allErrs, ValidateAffinityInPodAnnotations(annotations, fldPath)...)
}
if hostname, exists := annotations[utilpod.PodHostnameAnnotation]; exists && !validation.IsDNS1123Label(hostname) {
allErrs = append(allErrs, field.Invalid(fldPath, utilpod.PodHostnameAnnotation, DNS1123LabelErrorMsg))
}
if subdomain, exists := annotations[utilpod.PodSubdomainAnnotation]; exists && !validation.IsDNS1123Label(subdomain) {
allErrs = append(allErrs, field.Invalid(fldPath, utilpod.PodSubdomainAnnotation, DNS1123LabelErrorMsg))
}
return allErrs
}
func ValidateEndpointsSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
hostnamesMap, exists := annotations[endpoints.PodHostnamesAnnotation]
if exists && !isValidHostnamesMap(hostnamesMap) {
allErrs = append(allErrs, field.Invalid(fldPath, endpoints.PodHostnamesAnnotation,
`must be a valid json representation of map[string(IP)][HostRecord] e.g. "{"10.245.1.6":{"HostName":"my-webserver"}}"`))
}
return allErrs
}
@ -1090,6 +1117,8 @@ func validateVolumeMounts(mounts []api.VolumeMount, volumes sets.String, fldPath
}
if len(mnt.MountPath) == 0 {
allErrs = append(allErrs, field.Required(idxPath.Child("mountPath"), ""))
} else if strings.Contains(mnt.MountPath, ":") {
allErrs = append(allErrs, field.Invalid(idxPath.Child("mountPath"), mnt.MountPath, "must not contain ':'"))
}
}
return allErrs
@ -1352,7 +1381,9 @@ func validateImagePullSecrets(imagePullSecrets []api.LocalObjectReference, fldPa
// ValidatePod tests if required fields in the pod are set.
func ValidatePod(pod *api.Pod) field.ErrorList {
allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, field.NewPath("metadata"))
fldPath := field.NewPath("metadata")
allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, fldPath)
allErrs = append(allErrs, ValidatePodSpecificAnnotations(pod.ObjectMeta.Annotations, fldPath.Child("annotations"))...)
allErrs = append(allErrs, ValidatePodSpec(&pod.Spec, field.NewPath("spec"))...)
return allErrs
}
@ -1516,8 +1547,9 @@ func ValidatePodSecurityContext(securityContext *api.PodSecurityContext, spec *a
// ValidatePodUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
// that cannot be changed.
func ValidatePodUpdate(newPod, oldPod *api.Pod) field.ErrorList {
allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, field.NewPath("metadata"))
fldPath := field.NewPath("metadata")
allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, fldPath)
allErrs = append(allErrs, ValidatePodSpecificAnnotations(newPod.ObjectMeta.Annotations, fldPath.Child("annotations"))...)
specPath := field.NewPath("spec")
if len(newPod.Spec.Containers) != len(oldPod.Spec.Containers) {
//TODO: Pinpoint the specific container that causes the invalid error after we have strategic merge diff
@ -1735,6 +1767,12 @@ func ValidateService(service *api.Service) field.ErrorList {
nodePorts[key] = true
}
_, err := apiservice.GetLoadBalancerSourceRanges(service.Annotations)
if err != nil {
v := service.Annotations[apiservice.AnnotationLoadBalancerSourceRangesKey]
allErrs = append(allErrs, field.Invalid(field.NewPath("metadata", "annotations").Key(apiservice.AnnotationLoadBalancerSourceRangesKey), v, "must be a comma separated list of CIDRs e.g. 192.168.0.0/16,10.0.0.0/8"))
}
return allErrs
}
@ -1770,11 +1808,14 @@ func validateServicePort(sp *api.ServicePort, requireName, isHeadlessService boo
allErrs = append(allErrs, field.Invalid(fldPath.Child("targetPort"), sp.TargetPort, PortNameErrorMsg))
}
if isHeadlessService {
if sp.TargetPort.Type == intstr.String || (sp.TargetPort.Type == intstr.Int && sp.Port != sp.TargetPort.IntValue()) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), sp.Port, "must be equal to targetPort when clusterIP = None"))
}
}
// in the v1 API, targetPorts on headless services were tolerated.
// once we have version-specific validation, we can reject this on newer API versions, but until then, we have to tolerate it for compatibility.
//
// if isHeadlessService {
// if sp.TargetPort.Type == intstr.String || (sp.TargetPort.Type == intstr.Int && sp.Port != sp.TargetPort.IntValue()) {
// allErrs = append(allErrs, field.Invalid(fldPath.Child("targetPort"), sp.TargetPort, "must be equal to the value of 'port' when clusterIP = None"))
// }
// }
return allErrs
}
@ -1817,6 +1858,7 @@ func ValidateReplicationControllerStatusUpdate(controller, oldController *api.Re
allErrs := ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata"))
statusPath := field.NewPath("status")
allErrs = append(allErrs, ValidateNonnegativeField(int64(controller.Status.Replicas), statusPath.Child("replicas"))...)
allErrs = append(allErrs, ValidateNonnegativeField(int64(controller.Status.FullyLabeledReplicas), statusPath.Child("fullyLabeledReplicas"))...)
allErrs = append(allErrs, ValidateNonnegativeField(int64(controller.Status.ObservedGeneration), statusPath.Child("observedGeneration"))...)
return allErrs
}
@ -1871,6 +1913,7 @@ func ValidatePodTemplateSpec(spec *api.PodTemplateSpec, fldPath *field.Path) fie
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateLabels(spec.Labels, fldPath.Child("labels"))...)
allErrs = append(allErrs, ValidateAnnotations(spec.Annotations, fldPath.Child("annotations"))...)
allErrs = append(allErrs, ValidatePodSpecificAnnotations(spec.Annotations, fldPath.Child("annotations"))...)
allErrs = append(allErrs, ValidatePodSpec(&spec.Spec, fldPath.Child("spec"))...)
return allErrs
}
@ -1968,6 +2011,57 @@ func validateResourceName(value string, fldPath *field.Path) field.ErrorList {
return field.ErrorList{}
}
// Validate container resource name
// Refer to docs/design/resources.md for more details.
func validateContainerResourceName(value string, fldPath *field.Path) field.ErrorList {
allErrs := validateResourceName(value, fldPath)
if len(strings.Split(value, "/")) == 1 {
if !api.IsStandardContainerResourceName(value) {
return append(allErrs, field.Invalid(fldPath, value, "must be a standard resource for containers"))
}
}
return field.ErrorList{}
}
// Validate resource names that can go in a resource quota
// Refer to docs/design/resources.md for more details.
func validateResourceQuotaResourceName(value string, fldPath *field.Path) field.ErrorList {
allErrs := validateResourceName(value, fldPath)
if len(strings.Split(value, "/")) == 1 {
if !api.IsStandardQuotaResourceName(value) {
return append(allErrs, field.Invalid(fldPath, value, isInvalidQuotaResource))
}
}
return field.ErrorList{}
}
// Validate limit range types
func validateLimitRangeTypeName(value string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if !validation.IsQualifiedName(value) {
return append(allErrs, field.Invalid(fldPath, value, qualifiedNameErrorMsg))
}
if len(strings.Split(value, "/")) == 1 {
if !api.IsStandardLimitRangeType(value) {
return append(allErrs, field.Invalid(fldPath, value, "must be a standard limit type or fully qualified"))
}
}
return allErrs
}
// Validate limit range resource name
// limit types (other than Pod/Container) could contain storage not just cpu or memory
func validateLimitRangeResourceName(limitType api.LimitType, value string, fldPath *field.Path) field.ErrorList {
switch limitType {
case api.LimitTypePod, api.LimitTypeContainer:
return validateContainerResourceName(value, fldPath)
default:
return validateResourceName(value, fldPath)
}
}
// ValidateLimitRange tests if required fields in the LimitRange are set.
func ValidateLimitRange(limitRange *api.LimitRange) field.ErrorList {
allErrs := ValidateObjectMeta(&limitRange.ObjectMeta, true, ValidateLimitRangeName, field.NewPath("metadata"))
@ -1978,6 +2072,8 @@ func ValidateLimitRange(limitRange *api.LimitRange) field.ErrorList {
for i := range limitRange.Spec.Limits {
idxPath := fldPath.Index(i)
limit := &limitRange.Spec.Limits[i]
allErrs = append(allErrs, validateLimitRangeTypeName(string(limit.Type), idxPath.Child("type"))...)
_, found := limitTypeSet[limit.Type]
if found {
allErrs = append(allErrs, field.Duplicate(idxPath.Child("type"), limit.Type))
@ -1992,12 +2088,12 @@ func ValidateLimitRange(limitRange *api.LimitRange) field.ErrorList {
maxLimitRequestRatios := map[string]resource.Quantity{}
for k, q := range limit.Max {
allErrs = append(allErrs, validateResourceName(string(k), idxPath.Child("max").Key(string(k)))...)
allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("max").Key(string(k)))...)
keys.Insert(string(k))
max[string(k)] = q
}
for k, q := range limit.Min {
allErrs = append(allErrs, validateResourceName(string(k), idxPath.Child("min").Key(string(k)))...)
allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("min").Key(string(k)))...)
keys.Insert(string(k))
min[string(k)] = q
}
@ -2011,19 +2107,19 @@ func ValidateLimitRange(limitRange *api.LimitRange) field.ErrorList {
}
} else {
for k, q := range limit.Default {
allErrs = append(allErrs, validateResourceName(string(k), idxPath.Child("default").Key(string(k)))...)
allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("default").Key(string(k)))...)
keys.Insert(string(k))
defaults[string(k)] = q
}
for k, q := range limit.DefaultRequest {
allErrs = append(allErrs, validateResourceName(string(k), idxPath.Child("defaultRequest").Key(string(k)))...)
allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("defaultRequest").Key(string(k)))...)
keys.Insert(string(k))
defaultRequests[string(k)] = q
}
}
for k, q := range limit.MaxLimitRequestRatio {
allErrs = append(allErrs, validateResourceName(string(k), idxPath.Child("maxLimitRequestRatio").Key(string(k)))...)
allErrs = append(allErrs, validateLimitRangeResourceName(limit.Type, string(k), idxPath.Child("maxLimitRequestRatio").Key(string(k)))...)
keys.Insert(string(k))
maxLimitRequestRatios[string(k)] = q
}
@ -2246,7 +2342,7 @@ func ValidateResourceRequirements(requirements *api.ResourceRequirements, fldPat
for resourceName, quantity := range requirements.Limits {
fldPath := limPath.Key(string(resourceName))
// Validate resource name.
allErrs = append(allErrs, validateResourceName(string(resourceName), fldPath)...)
allErrs = append(allErrs, validateContainerResourceName(string(resourceName), fldPath)...)
if api.IsStandardResourceName(string(resourceName)) {
allErrs = append(allErrs, validateBasicResource(quantity, fldPath.Key(string(resourceName)))...)
}
@ -2262,7 +2358,7 @@ func ValidateResourceRequirements(requirements *api.ResourceRequirements, fldPat
for resourceName, quantity := range requirements.Requests {
fldPath := reqPath.Key(string(resourceName))
// Validate resource name.
allErrs = append(allErrs, validateResourceName(string(resourceName), fldPath)...)
allErrs = append(allErrs, validateContainerResourceName(string(resourceName), fldPath)...)
if api.IsStandardResourceName(string(resourceName)) {
allErrs = append(allErrs, validateBasicResource(quantity, fldPath.Key(string(resourceName)))...)
}
@ -2270,6 +2366,41 @@ func ValidateResourceRequirements(requirements *api.ResourceRequirements, fldPat
return allErrs
}
// validateResourceQuotaScopes ensures that each enumerated hard resource constraint is valid for set of scopes
func validateResourceQuotaScopes(resourceQuota *api.ResourceQuota) field.ErrorList {
allErrs := field.ErrorList{}
if len(resourceQuota.Spec.Scopes) == 0 {
return allErrs
}
hardLimits := sets.NewString()
for k := range resourceQuota.Spec.Hard {
hardLimits.Insert(string(k))
}
fldPath := field.NewPath("spec", "scopes")
scopeSet := sets.NewString()
for _, scope := range resourceQuota.Spec.Scopes {
if !api.IsStandardResourceQuotaScope(string(scope)) {
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuota.Spec.Scopes, "unsupported scope"))
}
for _, k := range hardLimits.List() {
if api.IsStandardQuotaResourceName(k) && !api.IsResourceQuotaScopeValidForResource(scope, k) {
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuota.Spec.Scopes, "unsupported scope applied to resource"))
}
}
scopeSet.Insert(string(scope))
}
invalidScopePairs := []sets.String{
sets.NewString(string(api.ResourceQuotaScopeBestEffort), string(api.ResourceQuotaScopeNotBestEffort)),
sets.NewString(string(api.ResourceQuotaScopeTerminating), string(api.ResourceQuotaScopeNotTerminating)),
}
for _, invalidScopePair := range invalidScopePairs {
if scopeSet.HasAll(invalidScopePair.List()...) {
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuota.Spec.Scopes, "conflicting scopes"))
}
}
return allErrs
}
// ValidateResourceQuota tests if required fields in the ResourceQuota are set.
func ValidateResourceQuota(resourceQuota *api.ResourceQuota) field.ErrorList {
allErrs := ValidateObjectMeta(&resourceQuota.ObjectMeta, true, ValidateResourceQuotaName, field.NewPath("metadata"))
@ -2277,21 +2408,24 @@ func ValidateResourceQuota(resourceQuota *api.ResourceQuota) field.ErrorList {
fldPath := field.NewPath("spec", "hard")
for k, v := range resourceQuota.Spec.Hard {
resPath := fldPath.Key(string(k))
allErrs = append(allErrs, validateResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...)
}
allErrs = append(allErrs, validateResourceQuotaScopes(resourceQuota)...)
fldPath = field.NewPath("status", "hard")
for k, v := range resourceQuota.Status.Hard {
resPath := fldPath.Key(string(k))
allErrs = append(allErrs, validateResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...)
}
fldPath = field.NewPath("status", "used")
for k, v := range resourceQuota.Status.Used {
resPath := fldPath.Key(string(k))
allErrs = append(allErrs, validateResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...)
}
return allErrs
}
@ -2314,9 +2448,25 @@ func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *api.Resourc
fldPath := field.NewPath("spec", "hard")
for k, v := range newResourceQuota.Spec.Hard {
resPath := fldPath.Key(string(k))
allErrs = append(allErrs, validateResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...)
}
// ensure scopes cannot change, and that resources are still valid for scope
fldPath = field.NewPath("spec", "scopes")
oldScopes := sets.NewString()
newScopes := sets.NewString()
for _, scope := range newResourceQuota.Spec.Scopes {
newScopes.Insert(string(scope))
}
for _, scope := range oldResourceQuota.Spec.Scopes {
oldScopes.Insert(string(scope))
}
if !oldScopes.Equal(newScopes) {
allErrs = append(allErrs, field.Invalid(fldPath, newResourceQuota.Spec.Scopes, "field is immutable"))
}
allErrs = append(allErrs, validateResourceQuotaScopes(newResourceQuota)...)
newResourceQuota.Status = oldResourceQuota.Status
return allErrs
}
@ -2331,13 +2481,13 @@ func ValidateResourceQuotaStatusUpdate(newResourceQuota, oldResourceQuota *api.R
fldPath := field.NewPath("status", "hard")
for k, v := range newResourceQuota.Status.Hard {
resPath := fldPath.Key(string(k))
allErrs = append(allErrs, validateResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...)
}
fldPath = field.NewPath("status", "used")
for k, v := range newResourceQuota.Status.Used {
resPath := fldPath.Key(string(k))
allErrs = append(allErrs, validateResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...)
}
newResourceQuota.Spec = oldResourceQuota.Spec
@ -2412,6 +2562,7 @@ func ValidateNamespaceFinalizeUpdate(newNamespace, oldNamespace *api.Namespace)
// ValidateEndpoints tests if required fields are set.
func ValidateEndpoints(endpoints *api.Endpoints) field.ErrorList {
allErrs := ValidateObjectMeta(&endpoints.ObjectMeta, true, ValidateEndpointsName, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateEndpointsSpecificAnnotations(endpoints.Annotations, field.NewPath("annotations"))...)
allErrs = append(allErrs, validateEndpointSubsets(endpoints.Subsets, field.NewPath("subsets"))...)
return allErrs
}
@ -2495,6 +2646,7 @@ func validateEndpointPort(port *api.EndpointPort, requireName bool, fldPath *fie
func ValidateEndpointsUpdate(newEndpoints, oldEndpoints *api.Endpoints) field.ErrorList {
allErrs := ValidateObjectMetaUpdate(&newEndpoints.ObjectMeta, &oldEndpoints.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, validateEndpointSubsets(newEndpoints.Subsets, field.NewPath("subsets"))...)
allErrs = append(allErrs, ValidateEndpointsSpecificAnnotations(newEndpoints.Annotations, field.NewPath("annotations"))...)
return allErrs
}
@ -2560,3 +2712,24 @@ func ValidateLoadBalancerStatus(status *api.LoadBalancerStatus, fldPath *field.P
}
return allErrs
}
func isValidHostnamesMap(serializedPodHostNames string) bool {
if len(serializedPodHostNames) == 0 {
return false
}
podHostNames := map[string]endpoints.HostRecord{}
err := json.Unmarshal([]byte(serializedPodHostNames), &podHostNames)
if err != nil {
return false
}
for ip, hostRecord := range podHostNames {
if !validation.IsDNS1123Label(hostRecord.HostName) {
return false
}
if net.ParseIP(ip) == nil {
return false
}
}
return true
}

File diff suppressed because it is too large Load diff

View file

@ -24,8 +24,11 @@ import (
"strings"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery"
"k8s.io/kubernetes/pkg/util/sets"
)
var (
@ -43,8 +46,8 @@ var (
// envRequestedVersions represents the versions requested via the
// KUBE_API_VERSIONS environment variable. The install package of each group
// checks this list before add their versions to the latest package and
// Scheme.
envRequestedVersions = map[unversioned.GroupVersion]struct{}{}
// Scheme. This list is small and order matters, so represent as a slice
envRequestedVersions = []unversioned.GroupVersion{}
)
func init() {
@ -58,7 +61,7 @@ func init() {
glog.Fatalf("invalid api version: %s in KUBE_API_VERSIONS: %s.",
version, os.Getenv("KUBE_API_VERSIONS"))
}
envRequestedVersions[gv] = struct{}{}
envRequestedVersions = append(envRequestedVersions, gv)
}
}
}
@ -104,8 +107,12 @@ func IsAllowedVersion(v unversioned.GroupVersion) bool {
if len(envRequestedVersions) == 0 {
return true
}
_, found := envRequestedVersions[v]
return found
for _, envGV := range envRequestedVersions {
if v == envGV {
return true
}
}
return false
}
// IsEnabledVersion returns if a version is enabled.
@ -167,6 +174,80 @@ func GroupOrDie(group string) *apimachinery.GroupMeta {
return &groupMetaCopy
}
// RESTMapper returns a union RESTMapper of all known types with priorities chosen in the following order:
// 1. if KUBE_API_VERSIONS is specified, then KUBE_API_VERSIONS in order, OR
// 1. legacy kube group preferred version, extensions preferred version, metrics perferred version, legacy
// kube any version, extensions any version, metrics any version, all other groups alphabetical preferred version,
// all other groups alphabetical.
func RESTMapper(versionPatterns ...unversioned.GroupVersion) meta.RESTMapper {
unionMapper := meta.MultiRESTMapper{}
for enabledVersion := range enabledVersions {
groupMeta := groupMetaMap[enabledVersion.Group]
unionMapper = append(unionMapper, groupMeta.RESTMapper)
}
if len(versionPatterns) != 0 {
resourcePriority := []unversioned.GroupVersionResource{}
kindPriority := []unversioned.GroupVersionKind{}
for _, versionPriority := range versionPatterns {
resourcePriority = append(resourcePriority, versionPriority.WithResource(meta.AnyResource))
kindPriority = append(kindPriority, versionPriority.WithKind(meta.AnyKind))
}
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
if len(envRequestedVersions) != 0 {
resourcePriority := []unversioned.GroupVersionResource{}
kindPriority := []unversioned.GroupVersionKind{}
for _, versionPriority := range envRequestedVersions {
resourcePriority = append(resourcePriority, versionPriority.WithResource(meta.AnyResource))
kindPriority = append(kindPriority, versionPriority.WithKind(meta.AnyKind))
}
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
prioritizedGroups := []string{"", "extensions", "metrics"}
resourcePriority, kindPriority := prioritiesForGroups(prioritizedGroups...)
prioritizedGroupsSet := sets.NewString(prioritizedGroups...)
remainingGroups := sets.String{}
for enabledVersion := range enabledVersions {
if !prioritizedGroupsSet.Has(enabledVersion.Group) {
remainingGroups.Insert(enabledVersion.Group)
}
}
remainingResourcePriority, remainingKindPriority := prioritiesForGroups(remainingGroups.List()...)
resourcePriority = append(resourcePriority, remainingResourcePriority...)
kindPriority = append(kindPriority, remainingKindPriority...)
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
// prioritiesForGroups returns the resource and kind priorities for a PriorityRESTMapper, preferring the preferred version of each group first,
// then any non-preferred version of the group second.
func prioritiesForGroups(groups ...string) ([]unversioned.GroupVersionResource, []unversioned.GroupVersionKind) {
resourcePriority := []unversioned.GroupVersionResource{}
kindPriority := []unversioned.GroupVersionKind{}
for _, group := range groups {
availableVersions := EnabledVersionsForGroup(group)
if len(availableVersions) > 0 {
resourcePriority = append(resourcePriority, availableVersions[0].WithResource(meta.AnyResource))
kindPriority = append(kindPriority, availableVersions[0].WithKind(meta.AnyKind))
}
}
for _, group := range groups {
resourcePriority = append(resourcePriority, unversioned.GroupVersionResource{Group: group, Version: meta.AnyVersion, Resource: meta.AnyResource})
kindPriority = append(kindPriority, unversioned.GroupVersionKind{Group: group, Version: meta.AnyVersion, Kind: meta.AnyKind})
}
return resourcePriority, kindPriority
}
// AllPreferredGroupVersions returns the preferred versions of all registered
// groups in the form of "group1/version1,group2/version2,..."
func AllPreferredGroupVersions() string {
@ -185,7 +266,7 @@ func AllPreferredGroupVersions() string {
// the KUBE_API_VERSIONS environment variable, but not enabled.
func ValidateEnvRequestedVersions() []unversioned.GroupVersion {
var missingVersions []unversioned.GroupVersion
for v := range envRequestedVersions {
for _, v := range envRequestedVersions {
if _, found := enabledVersions[v]; !found {
missingVersions = append(missingVersions, v)
}

View file

@ -1,68 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package registered
import (
"testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery"
)
func TestAllPreferredGroupVersions(t *testing.T) {
testCases := []struct {
groupMetas []apimachinery.GroupMeta
expect string
}{
{
groupMetas: []apimachinery.GroupMeta{
{
GroupVersion: unversioned.GroupVersion{"group1", "v1"},
},
{
GroupVersion: unversioned.GroupVersion{"group2", "v2"},
},
{
GroupVersion: unversioned.GroupVersion{"", "v1"},
},
},
expect: "group1/v1,group2/v2,v1",
},
{
groupMetas: []apimachinery.GroupMeta{
{
GroupVersion: unversioned.GroupVersion{"", "v1"},
},
},
expect: "v1",
},
{
groupMetas: []apimachinery.GroupMeta{},
expect: "",
},
}
for _, testCase := range testCases {
for _, groupMeta := range testCase.groupMetas {
RegisterGroup(groupMeta)
}
output := AllPreferredGroupVersions()
if testCase.expect != output {
t.Errorf("Error. expect: %s, got: %s", testCase.expect, output)
}
reset()
}
}

View file

@ -16,7 +16,7 @@ limitations under the License.
package v1beta1
// This file contains a collection of methods that can be used from go-resful to
// This file contains a collection of methods that can be used from go-restful to
// generate Swagger API documentation for its models. Please read this PR for more
// information on the implementation: https://github.com/emicklei/go-restful/pull/215
//

View file

@ -1,64 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package validation
import (
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
"k8s.io/kubernetes/pkg/util/validation/field"
)
func ValidateSubjectAccessReviewSpec(spec authorizationapi.SubjectAccessReviewSpec, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if spec.ResourceAttributes != nil && spec.NonResourceAttributes != nil {
allErrs = append(allErrs, field.Invalid(fldPath.Child("nonResourceAttributes"), spec.NonResourceAttributes, `cannot be specified in combination with resourceAttributes`))
}
if spec.ResourceAttributes == nil && spec.NonResourceAttributes == nil {
allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceAttributes"), spec.NonResourceAttributes, `exactly one of nonResourceAttributes or resourceAttributes must be specified`))
}
if len(spec.User) == 0 && len(spec.Groups) == 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("user"), spec.User, `at least one of user or group must be specified`))
}
return allErrs
}
func ValidateSelfSubjectAccessReviewSpec(spec authorizationapi.SelfSubjectAccessReviewSpec, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if spec.ResourceAttributes != nil && spec.NonResourceAttributes != nil {
allErrs = append(allErrs, field.Invalid(fldPath.Child("nonResourceAttributes"), spec.NonResourceAttributes, `cannot be specified in combination with resourceAttributes`))
}
if spec.ResourceAttributes == nil && spec.NonResourceAttributes == nil {
allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceAttributes"), spec.NonResourceAttributes, `exactly one of nonResourceAttributes or resourceAttributes must be specified`))
}
return allErrs
}
func ValidateSubjectAccessReview(sar *authorizationapi.SubjectAccessReview) field.ErrorList {
allErrs := ValidateSubjectAccessReviewSpec(sar.Spec, field.NewPath("spec"))
return allErrs
}
func ValidateSelfSubjectAccessReview(sar *authorizationapi.SelfSubjectAccessReview) field.ErrorList {
allErrs := ValidateSelfSubjectAccessReviewSpec(sar.Spec, field.NewPath("spec"))
return allErrs
}
func ValidateLocalSubjectAccessReview(sar *authorizationapi.LocalSubjectAccessReview) field.ErrorList {
allErrs := ValidateSubjectAccessReviewSpec(sar.Spec, field.NewPath("spec"))
return allErrs
}

View file

@ -1,135 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package validation
import (
"strings"
"testing"
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
"k8s.io/kubernetes/pkg/util/validation/field"
)
func TestValidateSARSpec(t *testing.T) {
successCases := []authorizationapi.SubjectAccessReviewSpec{
{ResourceAttributes: &authorizationapi.ResourceAttributes{}, User: "me"},
{NonResourceAttributes: &authorizationapi.NonResourceAttributes{}, Groups: []string{"my-group"}},
}
for _, successCase := range successCases {
if errs := ValidateSubjectAccessReviewSpec(successCase, field.NewPath("spec")); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
}
errorCases := []struct {
name string
obj authorizationapi.SubjectAccessReviewSpec
msg string
}{
{
name: "neither request",
obj: authorizationapi.SubjectAccessReviewSpec{User: "me"},
msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified",
},
{
name: "both requests",
obj: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
User: "me",
},
msg: "cannot be specified in combination with resourceAttributes",
},
{
name: "no subject",
obj: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
},
msg: `spec.user: Invalid value: "": at least one of user or group must be specified`,
},
}
for _, c := range errorCases {
errs := ValidateSubjectAccessReviewSpec(c.obj, field.NewPath("spec"))
if len(errs) == 0 {
t.Errorf("%s: expected failure for %q", c.name, c.msg)
} else if !strings.Contains(errs[0].Error(), c.msg) {
t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg)
}
errs = ValidateSubjectAccessReview(&authorizationapi.SubjectAccessReview{Spec: c.obj})
if len(errs) == 0 {
t.Errorf("%s: expected failure for %q", c.name, c.msg)
} else if !strings.Contains(errs[0].Error(), c.msg) {
t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg)
}
errs = ValidateLocalSubjectAccessReview(&authorizationapi.LocalSubjectAccessReview{Spec: c.obj})
if len(errs) == 0 {
t.Errorf("%s: expected failure for %q", c.name, c.msg)
} else if !strings.Contains(errs[0].Error(), c.msg) {
t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg)
}
}
}
func TestValidateSelfSAR(t *testing.T) {
successCases := []authorizationapi.SelfSubjectAccessReviewSpec{
{ResourceAttributes: &authorizationapi.ResourceAttributes{}},
}
for _, successCase := range successCases {
if errs := ValidateSelfSubjectAccessReviewSpec(successCase, field.NewPath("spec")); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
}
errorCases := []struct {
name string
obj authorizationapi.SelfSubjectAccessReviewSpec
msg string
}{
{
name: "neither request",
obj: authorizationapi.SelfSubjectAccessReviewSpec{},
msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified",
},
{
name: "both requests",
obj: authorizationapi.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
},
msg: "cannot be specified in combination with resourceAttributes",
},
}
for _, c := range errorCases {
errs := ValidateSelfSubjectAccessReviewSpec(c.obj, field.NewPath("spec"))
if len(errs) == 0 {
t.Errorf("%s: expected failure for %q", c.name, c.msg)
} else if !strings.Contains(errs[0].Error(), c.msg) {
t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg)
}
errs = ValidateSelfSubjectAccessReview(&authorizationapi.SelfSubjectAccessReview{Spec: c.obj})
if len(errs) == 0 {
t.Errorf("%s: expected failure for %q", c.name, c.msg)
} else if !strings.Contains(errs[0].Error(), c.msg) {
t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg)
}
}
}

View file

@ -47,8 +47,11 @@ func AddToScheme(scheme *runtime.Scheme) {
// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) {
scheme.AddKnownTypes(SchemeGroupVersion,
&Scale{},
&extensions.HorizontalPodAutoscaler{},
&extensions.HorizontalPodAutoscalerList{},
&api.ListOptions{},
)
}
func (obj *Scale) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }

View file

@ -0,0 +1,794 @@
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// ************************************************************
// DO NOT EDIT.
// THIS FILE IS AUTO-GENERATED BY codecgen.
// ************************************************************
package autoscaling
import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg2_api "k8s.io/kubernetes/pkg/api"
pkg1_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
pkg3_types "k8s.io/kubernetes/pkg/types"
"reflect"
"runtime"
time "time"
)
const (
// ----- content types ----
codecSelferC_UTF81234 = 1
codecSelferC_RAW1234 = 0
// ----- value types used ----
codecSelferValueTypeArray1234 = 10
codecSelferValueTypeMap1234 = 9
// ----- containerStateValues ----
codecSelfer_containerMapKey1234 = 2
codecSelfer_containerMapValue1234 = 3
codecSelfer_containerMapEnd1234 = 4
codecSelfer_containerArrayElem1234 = 6
codecSelfer_containerArrayEnd1234 = 7
)
var (
codecSelferBitsize1234 = uint8(reflect.TypeOf(uint(0)).Bits())
codecSelferOnlyMapOrArrayEncodeToStructErr1234 = errors.New(`only encoded map or array can be decoded into a struct`)
)
type codecSelfer1234 struct{}
func init() {
if codec1978.GenVersion != 5 {
_, file, _, _ := runtime.Caller(0)
err := fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v",
5, codec1978.GenVersion, file)
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg2_api.ObjectMeta
var v1 pkg1_unversioned.TypeMeta
var v2 pkg3_types.UID
var v3 time.Time
_, _, _, _ = v0, v1, v2, v3
}
}
func (x *Scale) CodecEncodeSelf(e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
if x == nil {
r.EncodeNil()
} else {
yym1 := z.EncBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.EncExt(x) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [5]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[0] = true
yyq2[1] = true
yyq2[2] = true
yyq2[3] = x.Kind != ""
yyq2[4] = x.APIVersion != ""
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(5)
} else {
yynn2 = 0
for _, b := range yyq2 {
if b {
yynn2++
}
}
r.EncodeMapStart(yynn2)
yynn2 = 0
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[0] {
yy4 := &x.ObjectMeta
yy4.CodecEncodeSelf(e)
} else {
r.EncodeNil()
}
} else {
if yyq2[0] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("metadata"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yy6 := &x.ObjectMeta
yy6.CodecEncodeSelf(e)
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[1] {
yy9 := &x.Spec
yy9.CodecEncodeSelf(e)
} else {
r.EncodeNil()
}
} else {
if yyq2[1] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("spec"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yy11 := &x.Spec
yy11.CodecEncodeSelf(e)
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[2] {
yy14 := &x.Status
yy14.CodecEncodeSelf(e)
} else {
r.EncodeNil()
}
} else {
if yyq2[2] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("status"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yy16 := &x.Status
yy16.CodecEncodeSelf(e)
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[3] {
yym19 := z.EncBinary()
_ = yym19
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.Kind))
}
} else {
r.EncodeString(codecSelferC_UTF81234, "")
}
} else {
if yyq2[3] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("kind"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym20 := z.EncBinary()
_ = yym20
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.Kind))
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[4] {
yym22 := z.EncBinary()
_ = yym22
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.APIVersion))
}
} else {
r.EncodeString(codecSelferC_UTF81234, "")
}
} else {
if yyq2[4] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("apiVersion"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym23 := z.EncBinary()
_ = yym23
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.APIVersion))
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
z.EncSendContainerState(codecSelfer_containerMapEnd1234)
}
}
}
}
func (x *Scale) CodecDecodeSelf(d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
yym1 := z.DecBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.DecExt(x) {
} else {
yyct2 := r.ContainerType()
if yyct2 == codecSelferValueTypeMap1234 {
yyl2 := r.ReadMapStart()
if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
} else {
x.codecDecodeSelfFromMap(yyl2, d)
}
} else if yyct2 == codecSelferValueTypeArray1234 {
yyl2 := r.ReadArrayStart()
if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
x.codecDecodeSelfFromArray(yyl2, d)
}
} else {
panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234)
}
}
}
func (x *Scale) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yys3Slc = z.DecScratchBuffer() // default slice to decode into
_ = yys3Slc
var yyhl3 bool = l >= 0
for yyj3 := 0; ; yyj3++ {
if yyhl3 {
if yyj3 >= l {
break
}
} else {
if r.CheckBreak() {
break
}
}
z.DecSendContainerState(codecSelfer_containerMapKey1234)
yys3Slc = r.DecodeBytes(yys3Slc, true, true)
yys3 := string(yys3Slc)
z.DecSendContainerState(codecSelfer_containerMapValue1234)
switch yys3 {
case "metadata":
if r.TryDecodeAsNil() {
x.ObjectMeta = pkg2_api.ObjectMeta{}
} else {
yyv4 := &x.ObjectMeta
yyv4.CodecDecodeSelf(d)
}
case "spec":
if r.TryDecodeAsNil() {
x.Spec = ScaleSpec{}
} else {
yyv5 := &x.Spec
yyv5.CodecDecodeSelf(d)
}
case "status":
if r.TryDecodeAsNil() {
x.Status = ScaleStatus{}
} else {
yyv6 := &x.Status
yyv6.CodecDecodeSelf(d)
}
case "kind":
if r.TryDecodeAsNil() {
x.Kind = ""
} else {
x.Kind = string(r.DecodeString())
}
case "apiVersion":
if r.TryDecodeAsNil() {
x.APIVersion = ""
} else {
x.APIVersion = string(r.DecodeString())
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
} // end for yyj3
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
}
func (x *Scale) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj9 int
var yyb9 bool
var yyhl9 bool = l >= 0
yyj9++
if yyhl9 {
yyb9 = yyj9 > l
} else {
yyb9 = r.CheckBreak()
}
if yyb9 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.ObjectMeta = pkg2_api.ObjectMeta{}
} else {
yyv10 := &x.ObjectMeta
yyv10.CodecDecodeSelf(d)
}
yyj9++
if yyhl9 {
yyb9 = yyj9 > l
} else {
yyb9 = r.CheckBreak()
}
if yyb9 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Spec = ScaleSpec{}
} else {
yyv11 := &x.Spec
yyv11.CodecDecodeSelf(d)
}
yyj9++
if yyhl9 {
yyb9 = yyj9 > l
} else {
yyb9 = r.CheckBreak()
}
if yyb9 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Status = ScaleStatus{}
} else {
yyv12 := &x.Status
yyv12.CodecDecodeSelf(d)
}
yyj9++
if yyhl9 {
yyb9 = yyj9 > l
} else {
yyb9 = r.CheckBreak()
}
if yyb9 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Kind = ""
} else {
x.Kind = string(r.DecodeString())
}
yyj9++
if yyhl9 {
yyb9 = yyj9 > l
} else {
yyb9 = r.CheckBreak()
}
if yyb9 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.APIVersion = ""
} else {
x.APIVersion = string(r.DecodeString())
}
for {
yyj9++
if yyhl9 {
yyb9 = yyj9 > l
} else {
yyb9 = r.CheckBreak()
}
if yyb9 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj9-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}
func (x *ScaleSpec) CodecEncodeSelf(e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
if x == nil {
r.EncodeNil()
} else {
yym1 := z.EncBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.EncExt(x) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [1]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[0] = x.Replicas != 0
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(1)
} else {
yynn2 = 0
for _, b := range yyq2 {
if b {
yynn2++
}
}
r.EncodeMapStart(yynn2)
yynn2 = 0
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[0] {
yym4 := z.EncBinary()
_ = yym4
if false {
} else {
r.EncodeInt(int64(x.Replicas))
}
} else {
r.EncodeInt(0)
}
} else {
if yyq2[0] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("replicas"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym5 := z.EncBinary()
_ = yym5
if false {
} else {
r.EncodeInt(int64(x.Replicas))
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
z.EncSendContainerState(codecSelfer_containerMapEnd1234)
}
}
}
}
func (x *ScaleSpec) CodecDecodeSelf(d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
yym1 := z.DecBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.DecExt(x) {
} else {
yyct2 := r.ContainerType()
if yyct2 == codecSelferValueTypeMap1234 {
yyl2 := r.ReadMapStart()
if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
} else {
x.codecDecodeSelfFromMap(yyl2, d)
}
} else if yyct2 == codecSelferValueTypeArray1234 {
yyl2 := r.ReadArrayStart()
if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
x.codecDecodeSelfFromArray(yyl2, d)
}
} else {
panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234)
}
}
}
func (x *ScaleSpec) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yys3Slc = z.DecScratchBuffer() // default slice to decode into
_ = yys3Slc
var yyhl3 bool = l >= 0
for yyj3 := 0; ; yyj3++ {
if yyhl3 {
if yyj3 >= l {
break
}
} else {
if r.CheckBreak() {
break
}
}
z.DecSendContainerState(codecSelfer_containerMapKey1234)
yys3Slc = r.DecodeBytes(yys3Slc, true, true)
yys3 := string(yys3Slc)
z.DecSendContainerState(codecSelfer_containerMapValue1234)
switch yys3 {
case "replicas":
if r.TryDecodeAsNil() {
x.Replicas = 0
} else {
x.Replicas = int(r.DecodeInt(codecSelferBitsize1234))
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
} // end for yyj3
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
}
func (x *ScaleSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj5 int
var yyb5 bool
var yyhl5 bool = l >= 0
yyj5++
if yyhl5 {
yyb5 = yyj5 > l
} else {
yyb5 = r.CheckBreak()
}
if yyb5 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Replicas = 0
} else {
x.Replicas = int(r.DecodeInt(codecSelferBitsize1234))
}
for {
yyj5++
if yyhl5 {
yyb5 = yyj5 > l
} else {
yyb5 = r.CheckBreak()
}
if yyb5 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj5-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}
func (x *ScaleStatus) CodecEncodeSelf(e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
if x == nil {
r.EncodeNil()
} else {
yym1 := z.EncBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.EncExt(x) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [2]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[1] = x.Selector != ""
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(2)
} else {
yynn2 = 1
for _, b := range yyq2 {
if b {
yynn2++
}
}
r.EncodeMapStart(yynn2)
yynn2 = 0
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
yym4 := z.EncBinary()
_ = yym4
if false {
} else {
r.EncodeInt(int64(x.Replicas))
}
} else {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("replicas"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym5 := z.EncBinary()
_ = yym5
if false {
} else {
r.EncodeInt(int64(x.Replicas))
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[1] {
yym7 := z.EncBinary()
_ = yym7
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.Selector))
}
} else {
r.EncodeString(codecSelferC_UTF81234, "")
}
} else {
if yyq2[1] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("selector"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym8 := z.EncBinary()
_ = yym8
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.Selector))
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
z.EncSendContainerState(codecSelfer_containerMapEnd1234)
}
}
}
}
func (x *ScaleStatus) CodecDecodeSelf(d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
yym1 := z.DecBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.DecExt(x) {
} else {
yyct2 := r.ContainerType()
if yyct2 == codecSelferValueTypeMap1234 {
yyl2 := r.ReadMapStart()
if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
} else {
x.codecDecodeSelfFromMap(yyl2, d)
}
} else if yyct2 == codecSelferValueTypeArray1234 {
yyl2 := r.ReadArrayStart()
if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
x.codecDecodeSelfFromArray(yyl2, d)
}
} else {
panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234)
}
}
}
func (x *ScaleStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yys3Slc = z.DecScratchBuffer() // default slice to decode into
_ = yys3Slc
var yyhl3 bool = l >= 0
for yyj3 := 0; ; yyj3++ {
if yyhl3 {
if yyj3 >= l {
break
}
} else {
if r.CheckBreak() {
break
}
}
z.DecSendContainerState(codecSelfer_containerMapKey1234)
yys3Slc = r.DecodeBytes(yys3Slc, true, true)
yys3 := string(yys3Slc)
z.DecSendContainerState(codecSelfer_containerMapValue1234)
switch yys3 {
case "replicas":
if r.TryDecodeAsNil() {
x.Replicas = 0
} else {
x.Replicas = int(r.DecodeInt(codecSelferBitsize1234))
}
case "selector":
if r.TryDecodeAsNil() {
x.Selector = ""
} else {
x.Selector = string(r.DecodeString())
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
} // end for yyj3
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
}
func (x *ScaleStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj6 int
var yyb6 bool
var yyhl6 bool = l >= 0
yyj6++
if yyhl6 {
yyb6 = yyj6 > l
} else {
yyb6 = r.CheckBreak()
}
if yyb6 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Replicas = 0
} else {
x.Replicas = int(r.DecodeInt(codecSelferBitsize1234))
}
yyj6++
if yyhl6 {
yyb6 = yyj6 > l
} else {
yyb6 = r.CheckBreak()
}
if yyb6 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Selector = ""
} else {
x.Selector = string(r.DecodeString())
}
for {
yyj6++
if yyhl6 {
yyb6 = yyj6 > l
} else {
yyb6 = r.CheckBreak()
}
if yyb6 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj6-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}

View file

@ -0,0 +1,53 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package autoscaling
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
)
// Scale represents a scaling request for a resource.
type Scale struct {
unversioned.TypeMeta `json:",inline"`
// Standard object metadata; More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata.
api.ObjectMeta `json:"metadata,omitempty"`
// defines the behavior of the scale. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status.
Spec ScaleSpec `json:"spec,omitempty"`
// current status of the scale. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status. Read-only.
Status ScaleStatus `json:"status,omitempty"`
}
// ScaleSpec describes the attributes of a scale subresource.
type ScaleSpec struct {
// desired number of instances for the scaled object.
Replicas int `json:"replicas,omitempty"`
}
// ScaleStatus represents the current status of a scale subresource.
type ScaleStatus struct {
// actual number of observed instances of the scaled object.
Replicas int `json:"replicas"`
// label query over pods that should match the replicas count. This is same
// as the label selector but in the string format to avoid introspection
// by clients. The string will be in the same format as the query-param syntax.
// More info: http://releases.k8s.io/release-1.2/docs/user-guide/labels.md#label-selectors
Selector string `json:"selector,omitempty"`
}

View file

@ -24,6 +24,7 @@ import (
api "k8s.io/kubernetes/pkg/api"
unversioned "k8s.io/kubernetes/pkg/api/unversioned"
v1 "k8s.io/kubernetes/pkg/api/v1"
autoscaling "k8s.io/kubernetes/pkg/apis/autoscaling"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
conversion "k8s.io/kubernetes/pkg/conversion"
)
@ -132,6 +133,54 @@ func Convert_v1_ObjectMeta_To_api_ObjectMeta(in *v1.ObjectMeta, out *api.ObjectM
return autoConvert_v1_ObjectMeta_To_api_ObjectMeta(in, out, s)
}
func autoConvert_autoscaling_Scale_To_v1_Scale(in *autoscaling.Scale, out *Scale, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*autoscaling.Scale))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := Convert_api_ObjectMeta_To_v1_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
return err
}
if err := Convert_autoscaling_ScaleSpec_To_v1_ScaleSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_autoscaling_ScaleStatus_To_v1_ScaleStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_autoscaling_Scale_To_v1_Scale(in *autoscaling.Scale, out *Scale, s conversion.Scope) error {
return autoConvert_autoscaling_Scale_To_v1_Scale(in, out, s)
}
func autoConvert_autoscaling_ScaleSpec_To_v1_ScaleSpec(in *autoscaling.ScaleSpec, out *ScaleSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*autoscaling.ScaleSpec))(in)
}
out.Replicas = int32(in.Replicas)
return nil
}
func Convert_autoscaling_ScaleSpec_To_v1_ScaleSpec(in *autoscaling.ScaleSpec, out *ScaleSpec, s conversion.Scope) error {
return autoConvert_autoscaling_ScaleSpec_To_v1_ScaleSpec(in, out, s)
}
func autoConvert_autoscaling_ScaleStatus_To_v1_ScaleStatus(in *autoscaling.ScaleStatus, out *ScaleStatus, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*autoscaling.ScaleStatus))(in)
}
out.Replicas = int32(in.Replicas)
out.Selector = in.Selector
return nil
}
func Convert_autoscaling_ScaleStatus_To_v1_ScaleStatus(in *autoscaling.ScaleStatus, out *ScaleStatus, s conversion.Scope) error {
return autoConvert_autoscaling_ScaleStatus_To_v1_ScaleStatus(in, out, s)
}
func autoConvert_v1_HorizontalPodAutoscaler_To_extensions_HorizontalPodAutoscaler(in *HorizontalPodAutoscaler, out *extensions.HorizontalPodAutoscaler, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*HorizontalPodAutoscaler))(in)
@ -232,6 +281,54 @@ func Convert_v1_HorizontalPodAutoscalerStatus_To_extensions_HorizontalPodAutosca
return autoConvert_v1_HorizontalPodAutoscalerStatus_To_extensions_HorizontalPodAutoscalerStatus(in, out, s)
}
func autoConvert_v1_Scale_To_autoscaling_Scale(in *Scale, out *autoscaling.Scale, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*Scale))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := Convert_v1_ObjectMeta_To_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
return err
}
if err := Convert_v1_ScaleSpec_To_autoscaling_ScaleSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_v1_ScaleStatus_To_autoscaling_ScaleStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_v1_Scale_To_autoscaling_Scale(in *Scale, out *autoscaling.Scale, s conversion.Scope) error {
return autoConvert_v1_Scale_To_autoscaling_Scale(in, out, s)
}
func autoConvert_v1_ScaleSpec_To_autoscaling_ScaleSpec(in *ScaleSpec, out *autoscaling.ScaleSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ScaleSpec))(in)
}
out.Replicas = int(in.Replicas)
return nil
}
func Convert_v1_ScaleSpec_To_autoscaling_ScaleSpec(in *ScaleSpec, out *autoscaling.ScaleSpec, s conversion.Scope) error {
return autoConvert_v1_ScaleSpec_To_autoscaling_ScaleSpec(in, out, s)
}
func autoConvert_v1_ScaleStatus_To_autoscaling_ScaleStatus(in *ScaleStatus, out *autoscaling.ScaleStatus, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ScaleStatus))(in)
}
out.Replicas = int(in.Replicas)
out.Selector = in.Selector
return nil
}
func Convert_v1_ScaleStatus_To_autoscaling_ScaleStatus(in *ScaleStatus, out *autoscaling.ScaleStatus, s conversion.Scope) error {
return autoConvert_v1_ScaleStatus_To_autoscaling_ScaleStatus(in, out, s)
}
func autoConvert_extensions_HorizontalPodAutoscaler_To_v1_HorizontalPodAutoscaler(in *extensions.HorizontalPodAutoscaler, out *HorizontalPodAutoscaler, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*extensions.HorizontalPodAutoscaler))(in)
@ -335,6 +432,9 @@ func Convert_extensions_HorizontalPodAutoscalerStatus_To_v1_HorizontalPodAutosca
func init() {
err := api.Scheme.AddGeneratedConversionFuncs(
autoConvert_api_ObjectMeta_To_v1_ObjectMeta,
autoConvert_autoscaling_ScaleSpec_To_v1_ScaleSpec,
autoConvert_autoscaling_ScaleStatus_To_v1_ScaleStatus,
autoConvert_autoscaling_Scale_To_v1_Scale,
autoConvert_extensions_HorizontalPodAutoscalerList_To_v1_HorizontalPodAutoscalerList,
autoConvert_extensions_HorizontalPodAutoscalerSpec_To_v1_HorizontalPodAutoscalerSpec,
autoConvert_extensions_HorizontalPodAutoscalerStatus_To_v1_HorizontalPodAutoscalerStatus,
@ -344,6 +444,9 @@ func init() {
autoConvert_v1_HorizontalPodAutoscalerStatus_To_extensions_HorizontalPodAutoscalerStatus,
autoConvert_v1_HorizontalPodAutoscaler_To_extensions_HorizontalPodAutoscaler,
autoConvert_v1_ObjectMeta_To_api_ObjectMeta,
autoConvert_v1_ScaleSpec_To_autoscaling_ScaleSpec,
autoConvert_v1_ScaleStatus_To_autoscaling_ScaleStatus,
autoConvert_v1_Scale_To_autoscaling_Scale,
)
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.

View file

@ -181,6 +181,33 @@ func deepCopy_v1_HorizontalPodAutoscalerStatus(in HorizontalPodAutoscalerStatus,
return nil
}
func deepCopy_v1_Scale(in Scale, out *Scale, c *conversion.Cloner) error {
if err := deepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
}
if err := deepCopy_v1_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
return err
}
if err := deepCopy_v1_ScaleSpec(in.Spec, &out.Spec, c); err != nil {
return err
}
if err := deepCopy_v1_ScaleStatus(in.Status, &out.Status, c); err != nil {
return err
}
return nil
}
func deepCopy_v1_ScaleSpec(in ScaleSpec, out *ScaleSpec, c *conversion.Cloner) error {
out.Replicas = in.Replicas
return nil
}
func deepCopy_v1_ScaleStatus(in ScaleStatus, out *ScaleStatus, c *conversion.Cloner) error {
out.Replicas = in.Replicas
out.Selector = in.Selector
return nil
}
func init() {
err := api.Scheme.AddGeneratedDeepCopyFuncs(
deepCopy_unversioned_ListMeta,
@ -192,6 +219,9 @@ func init() {
deepCopy_v1_HorizontalPodAutoscalerList,
deepCopy_v1_HorizontalPodAutoscalerSpec,
deepCopy_v1_HorizontalPodAutoscalerStatus,
deepCopy_v1_Scale,
deepCopy_v1_ScaleSpec,
deepCopy_v1_ScaleStatus,
)
if err != nil {
// if one of the deep copy functions is malformed, detect it immediately.

View file

@ -39,9 +39,11 @@ func addKnownTypes(scheme *runtime.Scheme) {
scheme.AddKnownTypes(SchemeGroupVersion,
&HorizontalPodAutoscaler{},
&HorizontalPodAutoscalerList{},
&Scale{},
&v1.ListOptions{},
)
}
func (obj *HorizontalPodAutoscaler) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *HorizontalPodAutoscalerList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *Scale) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }

View file

@ -1817,6 +1817,728 @@ func (x *HorizontalPodAutoscalerList) codecDecodeSelfFromArray(l int, d *codec19
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}
func (x *Scale) CodecEncodeSelf(e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
if x == nil {
r.EncodeNil()
} else {
yym1 := z.EncBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.EncExt(x) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [5]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[0] = true
yyq2[1] = true
yyq2[2] = true
yyq2[3] = x.Kind != ""
yyq2[4] = x.APIVersion != ""
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(5)
} else {
yynn2 = 0
for _, b := range yyq2 {
if b {
yynn2++
}
}
r.EncodeMapStart(yynn2)
yynn2 = 0
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[0] {
yy4 := &x.ObjectMeta
yy4.CodecEncodeSelf(e)
} else {
r.EncodeNil()
}
} else {
if yyq2[0] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("metadata"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yy6 := &x.ObjectMeta
yy6.CodecEncodeSelf(e)
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[1] {
yy9 := &x.Spec
yy9.CodecEncodeSelf(e)
} else {
r.EncodeNil()
}
} else {
if yyq2[1] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("spec"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yy11 := &x.Spec
yy11.CodecEncodeSelf(e)
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[2] {
yy14 := &x.Status
yy14.CodecEncodeSelf(e)
} else {
r.EncodeNil()
}
} else {
if yyq2[2] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("status"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yy16 := &x.Status
yy16.CodecEncodeSelf(e)
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[3] {
yym19 := z.EncBinary()
_ = yym19
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.Kind))
}
} else {
r.EncodeString(codecSelferC_UTF81234, "")
}
} else {
if yyq2[3] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("kind"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym20 := z.EncBinary()
_ = yym20
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.Kind))
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[4] {
yym22 := z.EncBinary()
_ = yym22
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.APIVersion))
}
} else {
r.EncodeString(codecSelferC_UTF81234, "")
}
} else {
if yyq2[4] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("apiVersion"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym23 := z.EncBinary()
_ = yym23
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.APIVersion))
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
z.EncSendContainerState(codecSelfer_containerMapEnd1234)
}
}
}
}
func (x *Scale) CodecDecodeSelf(d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
yym1 := z.DecBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.DecExt(x) {
} else {
yyct2 := r.ContainerType()
if yyct2 == codecSelferValueTypeMap1234 {
yyl2 := r.ReadMapStart()
if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
} else {
x.codecDecodeSelfFromMap(yyl2, d)
}
} else if yyct2 == codecSelferValueTypeArray1234 {
yyl2 := r.ReadArrayStart()
if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
x.codecDecodeSelfFromArray(yyl2, d)
}
} else {
panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234)
}
}
}
func (x *Scale) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yys3Slc = z.DecScratchBuffer() // default slice to decode into
_ = yys3Slc
var yyhl3 bool = l >= 0
for yyj3 := 0; ; yyj3++ {
if yyhl3 {
if yyj3 >= l {
break
}
} else {
if r.CheckBreak() {
break
}
}
z.DecSendContainerState(codecSelfer_containerMapKey1234)
yys3Slc = r.DecodeBytes(yys3Slc, true, true)
yys3 := string(yys3Slc)
z.DecSendContainerState(codecSelfer_containerMapValue1234)
switch yys3 {
case "metadata":
if r.TryDecodeAsNil() {
x.ObjectMeta = pkg2_v1.ObjectMeta{}
} else {
yyv4 := &x.ObjectMeta
yyv4.CodecDecodeSelf(d)
}
case "spec":
if r.TryDecodeAsNil() {
x.Spec = ScaleSpec{}
} else {
yyv5 := &x.Spec
yyv5.CodecDecodeSelf(d)
}
case "status":
if r.TryDecodeAsNil() {
x.Status = ScaleStatus{}
} else {
yyv6 := &x.Status
yyv6.CodecDecodeSelf(d)
}
case "kind":
if r.TryDecodeAsNil() {
x.Kind = ""
} else {
x.Kind = string(r.DecodeString())
}
case "apiVersion":
if r.TryDecodeAsNil() {
x.APIVersion = ""
} else {
x.APIVersion = string(r.DecodeString())
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
} // end for yyj3
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
}
func (x *Scale) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj9 int
var yyb9 bool
var yyhl9 bool = l >= 0
yyj9++
if yyhl9 {
yyb9 = yyj9 > l
} else {
yyb9 = r.CheckBreak()
}
if yyb9 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.ObjectMeta = pkg2_v1.ObjectMeta{}
} else {
yyv10 := &x.ObjectMeta
yyv10.CodecDecodeSelf(d)
}
yyj9++
if yyhl9 {
yyb9 = yyj9 > l
} else {
yyb9 = r.CheckBreak()
}
if yyb9 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Spec = ScaleSpec{}
} else {
yyv11 := &x.Spec
yyv11.CodecDecodeSelf(d)
}
yyj9++
if yyhl9 {
yyb9 = yyj9 > l
} else {
yyb9 = r.CheckBreak()
}
if yyb9 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Status = ScaleStatus{}
} else {
yyv12 := &x.Status
yyv12.CodecDecodeSelf(d)
}
yyj9++
if yyhl9 {
yyb9 = yyj9 > l
} else {
yyb9 = r.CheckBreak()
}
if yyb9 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Kind = ""
} else {
x.Kind = string(r.DecodeString())
}
yyj9++
if yyhl9 {
yyb9 = yyj9 > l
} else {
yyb9 = r.CheckBreak()
}
if yyb9 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.APIVersion = ""
} else {
x.APIVersion = string(r.DecodeString())
}
for {
yyj9++
if yyhl9 {
yyb9 = yyj9 > l
} else {
yyb9 = r.CheckBreak()
}
if yyb9 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj9-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}
func (x *ScaleSpec) CodecEncodeSelf(e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
if x == nil {
r.EncodeNil()
} else {
yym1 := z.EncBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.EncExt(x) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [1]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[0] = x.Replicas != 0
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(1)
} else {
yynn2 = 0
for _, b := range yyq2 {
if b {
yynn2++
}
}
r.EncodeMapStart(yynn2)
yynn2 = 0
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[0] {
yym4 := z.EncBinary()
_ = yym4
if false {
} else {
r.EncodeInt(int64(x.Replicas))
}
} else {
r.EncodeInt(0)
}
} else {
if yyq2[0] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("replicas"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym5 := z.EncBinary()
_ = yym5
if false {
} else {
r.EncodeInt(int64(x.Replicas))
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
z.EncSendContainerState(codecSelfer_containerMapEnd1234)
}
}
}
}
func (x *ScaleSpec) CodecDecodeSelf(d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
yym1 := z.DecBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.DecExt(x) {
} else {
yyct2 := r.ContainerType()
if yyct2 == codecSelferValueTypeMap1234 {
yyl2 := r.ReadMapStart()
if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
} else {
x.codecDecodeSelfFromMap(yyl2, d)
}
} else if yyct2 == codecSelferValueTypeArray1234 {
yyl2 := r.ReadArrayStart()
if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
x.codecDecodeSelfFromArray(yyl2, d)
}
} else {
panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234)
}
}
}
func (x *ScaleSpec) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yys3Slc = z.DecScratchBuffer() // default slice to decode into
_ = yys3Slc
var yyhl3 bool = l >= 0
for yyj3 := 0; ; yyj3++ {
if yyhl3 {
if yyj3 >= l {
break
}
} else {
if r.CheckBreak() {
break
}
}
z.DecSendContainerState(codecSelfer_containerMapKey1234)
yys3Slc = r.DecodeBytes(yys3Slc, true, true)
yys3 := string(yys3Slc)
z.DecSendContainerState(codecSelfer_containerMapValue1234)
switch yys3 {
case "replicas":
if r.TryDecodeAsNil() {
x.Replicas = 0
} else {
x.Replicas = int32(r.DecodeInt(32))
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
} // end for yyj3
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
}
func (x *ScaleSpec) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj5 int
var yyb5 bool
var yyhl5 bool = l >= 0
yyj5++
if yyhl5 {
yyb5 = yyj5 > l
} else {
yyb5 = r.CheckBreak()
}
if yyb5 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Replicas = 0
} else {
x.Replicas = int32(r.DecodeInt(32))
}
for {
yyj5++
if yyhl5 {
yyb5 = yyj5 > l
} else {
yyb5 = r.CheckBreak()
}
if yyb5 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj5-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}
func (x *ScaleStatus) CodecEncodeSelf(e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
if x == nil {
r.EncodeNil()
} else {
yym1 := z.EncBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.EncExt(x) {
} else {
yysep2 := !z.EncBinary()
yy2arr2 := z.EncBasicHandle().StructToArray
var yyq2 [2]bool
_, _, _ = yysep2, yyq2, yy2arr2
const yyr2 bool = false
yyq2[1] = x.Selector != ""
var yynn2 int
if yyr2 || yy2arr2 {
r.EncodeArrayStart(2)
} else {
yynn2 = 1
for _, b := range yyq2 {
if b {
yynn2++
}
}
r.EncodeMapStart(yynn2)
yynn2 = 0
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
yym4 := z.EncBinary()
_ = yym4
if false {
} else {
r.EncodeInt(int64(x.Replicas))
}
} else {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("replicas"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym5 := z.EncBinary()
_ = yym5
if false {
} else {
r.EncodeInt(int64(x.Replicas))
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayElem1234)
if yyq2[1] {
yym7 := z.EncBinary()
_ = yym7
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.Selector))
}
} else {
r.EncodeString(codecSelferC_UTF81234, "")
}
} else {
if yyq2[1] {
z.EncSendContainerState(codecSelfer_containerMapKey1234)
r.EncodeString(codecSelferC_UTF81234, string("selector"))
z.EncSendContainerState(codecSelfer_containerMapValue1234)
yym8 := z.EncBinary()
_ = yym8
if false {
} else {
r.EncodeString(codecSelferC_UTF81234, string(x.Selector))
}
}
}
if yyr2 || yy2arr2 {
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
z.EncSendContainerState(codecSelfer_containerMapEnd1234)
}
}
}
}
func (x *ScaleStatus) CodecDecodeSelf(d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
yym1 := z.DecBinary()
_ = yym1
if false {
} else if z.HasExtensions() && z.DecExt(x) {
} else {
yyct2 := r.ContainerType()
if yyct2 == codecSelferValueTypeMap1234 {
yyl2 := r.ReadMapStart()
if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
} else {
x.codecDecodeSelfFromMap(yyl2, d)
}
} else if yyct2 == codecSelferValueTypeArray1234 {
yyl2 := r.ReadArrayStart()
if yyl2 == 0 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
} else {
x.codecDecodeSelfFromArray(yyl2, d)
}
} else {
panic(codecSelferOnlyMapOrArrayEncodeToStructErr1234)
}
}
}
func (x *ScaleStatus) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yys3Slc = z.DecScratchBuffer() // default slice to decode into
_ = yys3Slc
var yyhl3 bool = l >= 0
for yyj3 := 0; ; yyj3++ {
if yyhl3 {
if yyj3 >= l {
break
}
} else {
if r.CheckBreak() {
break
}
}
z.DecSendContainerState(codecSelfer_containerMapKey1234)
yys3Slc = r.DecodeBytes(yys3Slc, true, true)
yys3 := string(yys3Slc)
z.DecSendContainerState(codecSelfer_containerMapValue1234)
switch yys3 {
case "replicas":
if r.TryDecodeAsNil() {
x.Replicas = 0
} else {
x.Replicas = int32(r.DecodeInt(32))
}
case "selector":
if r.TryDecodeAsNil() {
x.Selector = ""
} else {
x.Selector = string(r.DecodeString())
}
default:
z.DecStructFieldNotFound(-1, yys3)
} // end switch yys3
} // end for yyj3
z.DecSendContainerState(codecSelfer_containerMapEnd1234)
}
func (x *ScaleStatus) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
var yyj6 int
var yyb6 bool
var yyhl6 bool = l >= 0
yyj6++
if yyhl6 {
yyb6 = yyj6 > l
} else {
yyb6 = r.CheckBreak()
}
if yyb6 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Replicas = 0
} else {
x.Replicas = int32(r.DecodeInt(32))
}
yyj6++
if yyhl6 {
yyb6 = yyj6 > l
} else {
yyb6 = r.CheckBreak()
}
if yyb6 {
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
return
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Selector = ""
} else {
x.Selector = string(r.DecodeString())
}
for {
yyj6++
if yyhl6 {
yyb6 = yyj6 > l
} else {
yyb6 = r.CheckBreak()
}
if yyb6 {
break
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
z.DecStructFieldNotFound(yyj6-1, "")
}
z.DecSendContainerState(codecSelfer_containerArrayEnd1234)
}
func (x codecSelfer1234) encSliceHorizontalPodAutoscaler(v []HorizontalPodAutoscaler, e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)

View file

@ -23,9 +23,9 @@ import (
// CrossVersionObjectReference contains enough information to let you identify the referred resource.
type CrossVersionObjectReference struct {
// Kind of the referent; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds"
// Kind of the referent; More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds"
Kind string `json:"kind"`
// Name of the referent; More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names
// Name of the referent; More info: http://releases.k8s.io/release-1.2/docs/user-guide/identifiers.md#names
Name string `json:"name"`
// API version of the referent
APIVersion string `json:"apiVersion,omitempty"`
@ -41,6 +41,7 @@ type HorizontalPodAutoscalerSpec struct {
// upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas.
MaxReplicas int32 `json:"maxReplicas"`
// target average CPU utilization (represented as a percentage of requested CPU) over all the pods;
// if not specified the default autoscaling policy will be used.
TargetCPUUtilizationPercentage *int32 `json:"targetCPUUtilizationPercentage,omitempty"`
}
@ -67,10 +68,10 @@ type HorizontalPodAutoscalerStatus struct {
// configuration of a horizontal pod autoscaler.
type HorizontalPodAutoscaler struct {
unversioned.TypeMeta `json:",inline"`
// Standard object metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
// Standard object metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata
v1.ObjectMeta `json:"metadata,omitempty"`
// behaviour of autoscaler. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status.
// behaviour of autoscaler. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status.
Spec HorizontalPodAutoscalerSpec `json:"spec,omitempty"`
// current information about the autoscaler.
@ -86,3 +87,34 @@ type HorizontalPodAutoscalerList struct {
// list of horizontal pod autoscaler objects.
Items []HorizontalPodAutoscaler `json:"items"`
}
// Scale represents a scaling request for a resource.
type Scale struct {
unversioned.TypeMeta `json:",inline"`
// Standard object metadata; More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata.
v1.ObjectMeta `json:"metadata,omitempty"`
// defines the behavior of the scale. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status.
Spec ScaleSpec `json:"spec,omitempty"`
// current status of the scale. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status. Read-only.
Status ScaleStatus `json:"status,omitempty"`
}
// ScaleSpec describes the attributes of a scale subresource.
type ScaleSpec struct {
// desired number of instances for the scaled object.
Replicas int32 `json:"replicas,omitempty"`
}
// ScaleStatus represents the current status of a scale subresource.
type ScaleStatus struct {
// actual number of observed instances of the scaled object.
Replicas int32 `json:"replicas"`
// label query over pods that should match the replicas count. This is same
// as the label selector but in the string format to avoid introspection
// by clients. The string will be in the same format as the query-param syntax.
// More info about label selectors: http://releases.k8s.io/release-1.2/docs/user-guide/labels.md#label-selectors
Selector string `json:"selector,omitempty"`
}

View file

@ -16,7 +16,7 @@ limitations under the License.
package v1
// This file contains a collection of methods that can be used from go-resful to
// This file contains a collection of methods that can be used from go-restful to
// generate Swagger API documentation for its models. Please read this PR for more
// information on the implementation: https://github.com/emicklei/go-restful/pull/215
//
@ -29,8 +29,8 @@ package v1
// AUTO-GENERATED FUNCTIONS START HERE
var map_CrossVersionObjectReference = map[string]string{
"": "CrossVersionObjectReference contains enough information to let you identify the referred resource.",
"kind": "Kind of the referent; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds\"",
"name": "Name of the referent; More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names",
"kind": "Kind of the referent; More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#types-kinds\"",
"name": "Name of the referent; More info: http://releases.k8s.io/release-1.2/docs/user-guide/identifiers.md#names",
"apiVersion": "API version of the referent",
}
@ -40,8 +40,8 @@ func (CrossVersionObjectReference) SwaggerDoc() map[string]string {
var map_HorizontalPodAutoscaler = map[string]string{
"": "configuration of a horizontal pod autoscaler.",
"metadata": "Standard object metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
"spec": "behaviour of autoscaler. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status.",
"metadata": "Standard object metadata. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata",
"spec": "behaviour of autoscaler. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status.",
"status": "current information about the autoscaler.",
}
@ -64,7 +64,7 @@ var map_HorizontalPodAutoscalerSpec = map[string]string{
"scaleTargetRef": "reference to scaled resource; horizontal pod autoscaler will learn the current resource consumption and will set the desired number of pods by using its Scale subresource.",
"minReplicas": "lower limit for the number of pods that can be set by the autoscaler, default 1.",
"maxReplicas": "upper limit for the number of pods that can be set by the autoscaler; cannot be smaller than MinReplicas.",
"targetCPUUtilizationPercentage": "target average CPU utilization (represented as a percentage of requested CPU) over all the pods;",
"targetCPUUtilizationPercentage": "target average CPU utilization (represented as a percentage of requested CPU) over all the pods; if not specified the default autoscaling policy will be used.",
}
func (HorizontalPodAutoscalerSpec) SwaggerDoc() map[string]string {
@ -84,4 +84,34 @@ func (HorizontalPodAutoscalerStatus) SwaggerDoc() map[string]string {
return map_HorizontalPodAutoscalerStatus
}
var map_Scale = map[string]string{
"": "Scale represents a scaling request for a resource.",
"metadata": "Standard object metadata; More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#metadata.",
"spec": "defines the behavior of the scale. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status.",
"status": "current status of the scale. More info: http://releases.k8s.io/release-1.2/docs/devel/api-conventions.md#spec-and-status. Read-only.",
}
func (Scale) SwaggerDoc() map[string]string {
return map_Scale
}
var map_ScaleSpec = map[string]string{
"": "ScaleSpec describes the attributes of a scale subresource.",
"replicas": "desired number of instances for the scaled object.",
}
func (ScaleSpec) SwaggerDoc() map[string]string {
return map_ScaleSpec
}
var map_ScaleStatus = map[string]string{
"": "ScaleStatus represents the current status of a scale subresource.",
"replicas": "actual number of observed instances of the scaled object.",
"selector": "label query over pods that should match the replicas count. This is same as the label selector but in the string format to avoid introspection by clients. The string will be in the same format as the query-param syntax. More info about label selectors: http://releases.k8s.io/release-1.2/docs/user-guide/labels.md#label-selectors",
}
func (ScaleStatus) SwaggerDoc() map[string]string {
return map_ScaleStatus
}
// AUTO-GENERATED FUNCTIONS END HERE

View file

@ -1,5 +1,3 @@
// +build !windows
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
@ -16,12 +14,16 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package editor
// DO NOT EDIT. THIS FILE IS AUTO-GENERATED BY $KUBEROOT/hack/update-generated-deep-copies.sh.
import (
"os"
"syscall"
)
package batch
// childSignals are the allowed signals that can be sent to children in Unix variant OS's
var childSignals = []os.Signal{syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT}
import api "k8s.io/kubernetes/pkg/api"
func init() {
err := api.Scheme.AddGeneratedDeepCopyFuncs()
if err != nil {
// if one of the deep copy functions is malformed, detect it immediately.
panic(err)
}
}

View file

@ -0,0 +1,129 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package install installs the batch API group, making it available as
// an option to all of the API encoding/decoding machinery.
package install
import (
"fmt"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/batch/v1"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/sets"
)
const importPrefix = "k8s.io/kubernetes/pkg/apis/batch"
var accessor = meta.NewAccessor()
// availableVersions lists all known external versions for this group from most preferred to least preferred
var availableVersions = []unversioned.GroupVersion{v1.SchemeGroupVersion}
func init() {
registered.RegisterVersions(availableVersions)
externalVersions := []unversioned.GroupVersion{}
for _, v := range availableVersions {
if registered.IsAllowedVersion(v) {
externalVersions = append(externalVersions, v)
}
}
if len(externalVersions) == 0 {
glog.V(4).Infof("No version is registered for group %v", batch.GroupName)
return
}
if err := registered.EnableVersions(externalVersions...); err != nil {
glog.V(4).Infof("%v", err)
return
}
if err := enableVersions(externalVersions); err != nil {
glog.V(4).Infof("%v", err)
return
}
}
// TODO: enableVersions should be centralized rather than spread in each API
// group.
// We can combine registered.RegisterVersions, registered.EnableVersions and
// registered.RegisterGroup once we have moved enableVersions there.
func enableVersions(externalVersions []unversioned.GroupVersion) error {
addVersionsToScheme(externalVersions...)
preferredExternalVersion := externalVersions[0]
groupMeta := apimachinery.GroupMeta{
GroupVersion: preferredExternalVersion,
GroupVersions: externalVersions,
RESTMapper: newRESTMapper(externalVersions),
SelfLinker: runtime.SelfLinker(accessor),
InterfacesFor: interfacesFor,
}
if err := registered.RegisterGroup(groupMeta); err != nil {
return err
}
api.RegisterRESTMapper(groupMeta.RESTMapper)
return nil
}
func newRESTMapper(externalVersions []unversioned.GroupVersion) meta.RESTMapper {
// the list of kinds that are scoped at the root of the api hierarchy
// if a kind is not enumerated here, it is assumed to have a namespace scope
rootScoped := sets.NewString()
ignoredKinds := sets.NewString()
return api.NewDefaultRESTMapper(externalVersions, interfacesFor, importPrefix, ignoredKinds, rootScoped)
}
// interfacesFor returns the default Codec and ResourceVersioner for a given version
// string, or an error if the version is not known.
func interfacesFor(version unversioned.GroupVersion) (*meta.VersionInterfaces, error) {
switch version {
case v1.SchemeGroupVersion:
return &meta.VersionInterfaces{
ObjectConvertor: api.Scheme,
MetadataAccessor: accessor,
}, nil
default:
g, _ := registered.Group(batch.GroupName)
return nil, fmt.Errorf("unsupported storage version: %s (valid: %v)", version, g.GroupVersions)
}
}
func addVersionsToScheme(externalVersions ...unversioned.GroupVersion) {
// add the internal version to Scheme
batch.AddToScheme(api.Scheme)
// add the enabled external versions to Scheme
for _, v := range externalVersions {
if !registered.IsEnabledVersion(v) {
glog.Errorf("Version %s is not enabled, so it will not be added to the Scheme.", v)
continue
}
switch v {
case v1.SchemeGroupVersion:
v1.AddToScheme(api.Scheme)
}
}
}

View file

@ -0,0 +1,54 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package batch
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/runtime"
)
// GroupName is the group name use in this package
const GroupName = "batch"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) unversioned.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns back a Group qualified GroupResource
func Resource(resource string) unversioned.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
func AddToScheme(scheme *runtime.Scheme) {
// Add the API to Scheme.
addKnownTypes(scheme)
}
// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) {
scheme.AddKnownTypes(SchemeGroupVersion,
&extensions.Job{},
&extensions.JobList{},
&api.ListOptions{},
)
}

Some files were not shown because too many files have changed in this diff Show more