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

@ -1,385 +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 cache
import (
"reflect"
"testing"
"time"
)
// helper function to reduce stuttering
func testPop(f *DeltaFIFO) testFifoObject {
return f.Pop().(Deltas).Newest().Object.(testFifoObject)
}
// keyLookupFunc adapts a raw function to be a KeyLookup.
type keyLookupFunc func() []string
// ListKeys just calls kl.
func (kl keyLookupFunc) ListKeys() []string {
return kl()
}
// GetByKey returns the key if it exists in the list returned by kl.
func (kl keyLookupFunc) GetByKey(key string) (interface{}, bool, error) {
for _, v := range kl() {
if v == key {
return key, true, nil
}
}
return nil, false, nil
}
func TestDeltaFIFO_basic(t *testing.T) {
f := NewDeltaFIFO(testFifoObjectKeyFunc, nil, nil)
const amount = 500
go func() {
for i := 0; i < amount; i++ {
f.Add(mkFifoObj(string([]rune{'a', rune(i)}), i+1))
}
}()
go func() {
for u := uint64(0); u < amount; u++ {
f.Add(mkFifoObj(string([]rune{'b', rune(u)}), u+1))
}
}()
lastInt := int(0)
lastUint := uint64(0)
for i := 0; i < amount*2; i++ {
switch obj := testPop(f).val.(type) {
case int:
if obj <= lastInt {
t.Errorf("got %v (int) out of order, last was %v", obj, lastInt)
}
lastInt = obj
case uint64:
if obj <= lastUint {
t.Errorf("got %v (uint) out of order, last was %v", obj, lastUint)
} else {
lastUint = obj
}
default:
t.Fatalf("unexpected type %#v", obj)
}
}
}
func TestDeltaFIFO_compressorWorks(t *testing.T) {
oldestTypes := []DeltaType{}
f := NewDeltaFIFO(
testFifoObjectKeyFunc,
// This function just keeps the most recent delta
// and puts deleted ones in the list.
DeltaCompressorFunc(func(d Deltas) Deltas {
if n := len(d); n > 1 {
oldestTypes = append(oldestTypes, d[0].Type)
d = d[1:]
}
return d
}),
nil,
)
f.Add(mkFifoObj("foo", 10))
f.Update(mkFifoObj("foo", 12))
f.Replace([]interface{}{mkFifoObj("foo", 20)}, "0")
f.Delete(mkFifoObj("foo", 22))
f.Add(mkFifoObj("foo", 25)) // flush the last one out
expect := []DeltaType{Added, Updated, Sync, Deleted}
if e, a := expect, oldestTypes; !reflect.DeepEqual(e, a) {
t.Errorf("Expected %#v, got %#v", e, a)
}
if e, a := (Deltas{{Added, mkFifoObj("foo", 25)}}), f.Pop().(Deltas); !reflect.DeepEqual(e, a) {
t.Fatalf("Expected %#v, got %#v", e, a)
}
}
func TestDeltaFIFO_addUpdate(t *testing.T) {
f := NewDeltaFIFO(testFifoObjectKeyFunc, nil, nil)
f.Add(mkFifoObj("foo", 10))
f.Update(mkFifoObj("foo", 12))
f.Delete(mkFifoObj("foo", 15))
if e, a := []interface{}{mkFifoObj("foo", 15)}, f.List(); !reflect.DeepEqual(e, a) {
t.Errorf("Expected %+v, got %+v", e, a)
}
if e, a := []string{"foo"}, f.ListKeys(); !reflect.DeepEqual(e, a) {
t.Errorf("Expected %+v, got %+v", e, a)
}
got := make(chan testFifoObject, 2)
go func() {
for {
obj := f.Pop().(Deltas).Newest().Object.(testFifoObject)
t.Logf("got a thing %#v", obj)
t.Logf("D len: %v", len(f.queue))
got <- obj
}
}()
first := <-got
if e, a := 15, first.val; e != a {
t.Errorf("Didn't get updated value (%v), got %v", e, a)
}
select {
case unexpected := <-got:
t.Errorf("Got second value %v", unexpected.val)
case <-time.After(50 * time.Millisecond):
}
_, exists, _ := f.Get(mkFifoObj("foo", ""))
if exists {
t.Errorf("item did not get removed")
}
}
func TestDeltaFIFO_enqueueingNoLister(t *testing.T) {
f := NewDeltaFIFO(testFifoObjectKeyFunc, nil, nil)
f.Add(mkFifoObj("foo", 10))
f.Update(mkFifoObj("bar", 15))
f.Add(mkFifoObj("qux", 17))
f.Delete(mkFifoObj("qux", 18))
// This delete does not enqueue anything because baz doesn't exist.
f.Delete(mkFifoObj("baz", 20))
expectList := []int{10, 15, 18}
for _, expect := range expectList {
if e, a := expect, testPop(f).val; e != a {
t.Errorf("Didn't get updated value (%v), got %v", e, a)
}
}
if e, a := 0, len(f.items); e != a {
t.Errorf("queue unexpectedly not empty: %v != %v\n%#v", e, a, f.items)
}
}
func TestDeltaFIFO_enqueueingWithLister(t *testing.T) {
f := NewDeltaFIFO(
testFifoObjectKeyFunc,
nil,
keyLookupFunc(func() []string {
return []string{"foo", "bar", "baz"}
}),
)
f.Add(mkFifoObj("foo", 10))
f.Update(mkFifoObj("bar", 15))
// This delete does enqueue the deletion, because "baz" is in the key lister.
f.Delete(mkFifoObj("baz", 20))
expectList := []int{10, 15, 20}
for _, expect := range expectList {
if e, a := expect, testPop(f).val; e != a {
t.Errorf("Didn't get updated value (%v), got %v", e, a)
}
}
if e, a := 0, len(f.items); e != a {
t.Errorf("queue unexpectedly not empty: %v != %v", e, a)
}
}
func TestDeltaFIFO_addReplace(t *testing.T) {
f := NewDeltaFIFO(testFifoObjectKeyFunc, nil, nil)
f.Add(mkFifoObj("foo", 10))
f.Replace([]interface{}{mkFifoObj("foo", 15)}, "0")
got := make(chan testFifoObject, 2)
go func() {
for {
got <- testPop(f)
}
}()
first := <-got
if e, a := 15, first.val; e != a {
t.Errorf("Didn't get updated value (%v), got %v", e, a)
}
select {
case unexpected := <-got:
t.Errorf("Got second value %v", unexpected.val)
case <-time.After(50 * time.Millisecond):
}
_, exists, _ := f.Get(mkFifoObj("foo", ""))
if exists {
t.Errorf("item did not get removed")
}
}
func TestDeltaFIFO_ReplaceMakesDeletions(t *testing.T) {
f := NewDeltaFIFO(
testFifoObjectKeyFunc,
nil,
keyLookupFunc(func() []string {
return []string{"foo", "bar", "baz"}
}),
)
f.Delete(mkFifoObj("baz", 10))
f.Replace([]interface{}{mkFifoObj("foo", 5)}, "0")
expectedList := []Deltas{
{{Deleted, mkFifoObj("baz", 10)}},
{{Sync, mkFifoObj("foo", 5)}},
// Since "bar" didn't have a delete event and wasn't in the Replace list
// it should get a tombstone key with the right Obj.
{{Deleted, DeletedFinalStateUnknown{Key: "bar", Obj: "bar"}}},
}
for _, expected := range expectedList {
cur := f.Pop().(Deltas)
if e, a := expected, cur; !reflect.DeepEqual(e, a) {
t.Errorf("Expected %#v, got %#v", e, a)
}
}
}
func TestDeltaFIFO_detectLineJumpers(t *testing.T) {
f := NewDeltaFIFO(testFifoObjectKeyFunc, nil, nil)
f.Add(mkFifoObj("foo", 10))
f.Add(mkFifoObj("bar", 1))
f.Add(mkFifoObj("foo", 11))
f.Add(mkFifoObj("foo", 13))
f.Add(mkFifoObj("zab", 30))
if e, a := 13, testPop(f).val; a != e {
t.Fatalf("expected %d, got %d", e, a)
}
f.Add(mkFifoObj("foo", 14)) // ensure foo doesn't jump back in line
if e, a := 1, testPop(f).val; a != e {
t.Fatalf("expected %d, got %d", e, a)
}
if e, a := 30, testPop(f).val; a != e {
t.Fatalf("expected %d, got %d", e, a)
}
if e, a := 14, testPop(f).val; a != e {
t.Fatalf("expected %d, got %d", e, a)
}
}
func TestDeltaFIFO_addIfNotPresent(t *testing.T) {
f := NewDeltaFIFO(testFifoObjectKeyFunc, nil, nil)
f.Add(mkFifoObj("b", 3))
b3 := f.Pop()
f.Add(mkFifoObj("c", 4))
c4 := f.Pop()
if e, a := 0, len(f.items); e != a {
t.Fatalf("Expected %v, got %v items in queue", e, a)
}
f.Add(mkFifoObj("a", 1))
f.Add(mkFifoObj("b", 2))
f.AddIfNotPresent(b3)
f.AddIfNotPresent(c4)
if e, a := 3, len(f.items); a != e {
t.Fatalf("expected queue length %d, got %d", e, a)
}
expectedValues := []int{1, 2, 4}
for _, expected := range expectedValues {
if actual := testPop(f).val; actual != expected {
t.Fatalf("expected value %d, got %d", expected, actual)
}
}
}
func TestDeltaFIFO_KeyOf(t *testing.T) {
f := DeltaFIFO{keyFunc: testFifoObjectKeyFunc}
table := []struct {
obj interface{}
key string
}{
{obj: testFifoObject{name: "A"}, key: "A"},
{obj: DeletedFinalStateUnknown{Key: "B", Obj: nil}, key: "B"},
{obj: Deltas{{Object: testFifoObject{name: "C"}}}, key: "C"},
{obj: Deltas{{Object: DeletedFinalStateUnknown{Key: "D", Obj: nil}}}, key: "D"},
}
for _, item := range table {
got, err := f.KeyOf(item.obj)
if err != nil {
t.Errorf("Unexpected error for %q: %v", item.obj, err)
continue
}
if e, a := item.key, got; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
}
}
func TestDeltaFIFO_HasSynced(t *testing.T) {
tests := []struct {
actions []func(f *DeltaFIFO)
expectedSynced bool
}{
{
actions: []func(f *DeltaFIFO){},
expectedSynced: false,
},
{
actions: []func(f *DeltaFIFO){
func(f *DeltaFIFO) { f.Add(mkFifoObj("a", 1)) },
},
expectedSynced: true,
},
{
actions: []func(f *DeltaFIFO){
func(f *DeltaFIFO) { f.Replace([]interface{}{}, "0") },
},
expectedSynced: true,
},
{
actions: []func(f *DeltaFIFO){
func(f *DeltaFIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") },
},
expectedSynced: false,
},
{
actions: []func(f *DeltaFIFO){
func(f *DeltaFIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") },
func(f *DeltaFIFO) { f.Pop() },
},
expectedSynced: false,
},
{
actions: []func(f *DeltaFIFO){
func(f *DeltaFIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") },
func(f *DeltaFIFO) { f.Pop() },
func(f *DeltaFIFO) { f.Pop() },
},
expectedSynced: true,
},
}
for i, test := range tests {
f := NewDeltaFIFO(testFifoObjectKeyFunc, nil, nil)
for _, action := range test.actions {
action(f)
}
if e, a := test.expectedSynced, f.HasSynced(); a != e {
t.Errorf("test case %v failed, expected: %v , got %v", i, e, a)
}
}
}

View file

@ -17,11 +17,11 @@ limitations under the License.
package cache
import (
"sync"
"time"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/runtime"
)
// ExpirationCache implements the store interface
@ -29,12 +29,20 @@ import (
// a. The key is computed based off the original item/keyFunc
// b. The value inserted under that key is the timestamped item
// 2. Expiration happens lazily on read based on the expiration policy
// a. No item can be inserted into the store while we're expiring
// *any* item in the cache.
// 3. Time-stamps are stripped off unexpired entries before return
// Note that the ExpirationCache is inherently slower than a normal
// threadSafeStore because it takes a write lock every time it checks if
// an item has expired.
type ExpirationCache struct {
cacheStorage ThreadSafeStore
keyFunc KeyFunc
clock util.Clock
expirationPolicy ExpirationPolicy
// expirationLock is a write lock used to guarantee that we don't clobber
// newly inserted objects because of a stale expiration timestamp comparison
expirationLock sync.Mutex
}
// ExpirationPolicy dictates when an object expires. Currently only abstracted out
@ -68,7 +76,6 @@ type timestampedEntry struct {
// getTimestampedEntry returnes the timestampedEntry stored under the given key.
func (c *ExpirationCache) getTimestampedEntry(key string) (*timestampedEntry, bool) {
item, _ := c.cacheStorage.Get(key)
// TODO: Check the cast instead
if tsEntry, ok := item.(*timestampedEntry); ok {
return tsEntry, true
}
@ -76,24 +83,20 @@ func (c *ExpirationCache) getTimestampedEntry(key string) (*timestampedEntry, bo
}
// getOrExpire retrieves the object from the timestampedEntry if and only if it hasn't
// already expired. It kicks-off a go routine to delete expired objects from
// the store and sets exists=false.
// already expired. It holds a write lock across deletion.
func (c *ExpirationCache) getOrExpire(key string) (interface{}, bool) {
// Prevent all inserts from the time we deem an item as "expired" to when we
// delete it, so an un-expired item doesn't sneak in under the same key, just
// before the Delete.
c.expirationLock.Lock()
defer c.expirationLock.Unlock()
timestampedItem, exists := c.getTimestampedEntry(key)
if !exists {
return nil, false
}
if c.expirationPolicy.IsExpired(timestampedItem) {
glog.V(4).Infof("Entry %v: %+v has expired", key, timestampedItem.obj)
// Since expiration happens lazily on read, don't hold up
// the reader trying to acquire a write lock for the delete.
// The next reader will retry the delete even if this one
// fails; as long as we only return un-expired entries a
// reader doesn't need to wait for the result of the delete.
go func() {
defer runtime.HandleCrash()
c.cacheStorage.Delete(key)
}()
c.cacheStorage.Delete(key)
return nil, false
}
return timestampedItem.obj, true
@ -141,6 +144,8 @@ func (c *ExpirationCache) ListKeys() []string {
// Add timestamps an item and inserts it into the cache, overwriting entries
// that might exist under the same key.
func (c *ExpirationCache) Add(obj interface{}) error {
c.expirationLock.Lock()
defer c.expirationLock.Unlock()
key, err := c.keyFunc(obj)
if err != nil {
return KeyError{obj, err}
@ -157,6 +162,8 @@ func (c *ExpirationCache) Update(obj interface{}) error {
// Delete removes an item from the cache.
func (c *ExpirationCache) Delete(obj interface{}) error {
c.expirationLock.Lock()
defer c.expirationLock.Unlock()
key, err := c.keyFunc(obj)
if err != nil {
return KeyError{obj, err}
@ -169,6 +176,8 @@ func (c *ExpirationCache) Delete(obj interface{}) error {
// before attempting the replace operation. The replace operation will
// delete the contents of the ExpirationCache `c`.
func (c *ExpirationCache) Replace(list []interface{}, resourceVersion string) error {
c.expirationLock.Lock()
defer c.expirationLock.Unlock()
items := map[string]interface{}{}
ts := c.clock.Now()
for _, item := range list {

View file

@ -28,6 +28,7 @@ type fakeThreadSafeMap struct {
func (c *fakeThreadSafeMap) Delete(key string) {
if c.deletedKeys != nil {
c.ThreadSafeStore.Delete(key)
c.deletedKeys <- key
}
}

View file

@ -1,136 +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 cache
import (
"reflect"
"testing"
"time"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/util/wait"
)
func TestTTLExpirationBasic(t *testing.T) {
testObj := testStoreObject{id: "foo", val: "bar"}
deleteChan := make(chan string)
ttlStore := NewFakeExpirationStore(
testStoreKeyFunc, deleteChan,
&FakeExpirationPolicy{
NeverExpire: sets.NewString(),
RetrieveKeyFunc: func(obj interface{}) (string, error) {
return obj.(*timestampedEntry).obj.(testStoreObject).id, nil
},
},
util.RealClock{},
)
err := ttlStore.Add(testObj)
if err != nil {
t.Errorf("Unable to add obj %#v", testObj)
}
item, exists, err := ttlStore.Get(testObj)
if err != nil {
t.Errorf("Failed to get from store, %v", err)
}
if exists || item != nil {
t.Errorf("Got unexpected item %#v", item)
}
key, _ := testStoreKeyFunc(testObj)
select {
case delKey := <-deleteChan:
if delKey != key {
t.Errorf("Unexpected delete for key %s", key)
}
case <-time.After(wait.ForeverTestTimeout):
t.Errorf("Unexpected timeout waiting on delete")
}
close(deleteChan)
}
func TestTTLList(t *testing.T) {
testObjs := []testStoreObject{
{id: "foo", val: "bar"},
{id: "foo1", val: "bar1"},
{id: "foo2", val: "bar2"},
}
expireKeys := sets.NewString(testObjs[0].id, testObjs[2].id)
deleteChan := make(chan string)
defer close(deleteChan)
ttlStore := NewFakeExpirationStore(
testStoreKeyFunc, deleteChan,
&FakeExpirationPolicy{
NeverExpire: sets.NewString(testObjs[1].id),
RetrieveKeyFunc: func(obj interface{}) (string, error) {
return obj.(*timestampedEntry).obj.(testStoreObject).id, nil
},
},
util.RealClock{},
)
for _, obj := range testObjs {
err := ttlStore.Add(obj)
if err != nil {
t.Errorf("Unable to add obj %#v", obj)
}
}
listObjs := ttlStore.List()
if len(listObjs) != 1 || !reflect.DeepEqual(listObjs[0], testObjs[1]) {
t.Errorf("List returned unexpected results %#v", listObjs)
}
// Make sure all our deletes come through in an acceptable rate (1/100ms)
for expireKeys.Len() != 0 {
select {
case delKey := <-deleteChan:
if !expireKeys.Has(delKey) {
t.Errorf("Unexpected delete for key %s", delKey)
}
expireKeys.Delete(delKey)
case <-time.After(wait.ForeverTestTimeout):
t.Errorf("Unexpected timeout waiting on delete")
return
}
}
}
func TestTTLPolicy(t *testing.T) {
fakeTime := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
ttl := 30 * time.Second
exactlyOnTTL := fakeTime.Add(-ttl)
expiredTime := fakeTime.Add(-(ttl + 1))
policy := TTLPolicy{ttl, util.NewFakeClock(fakeTime)}
fakeTimestampedEntry := &timestampedEntry{obj: struct{}{}, timestamp: exactlyOnTTL}
if policy.IsExpired(fakeTimestampedEntry) {
t.Errorf("TTL cache should not expire entries exactly on ttl")
}
fakeTimestampedEntry.timestamp = fakeTime
if policy.IsExpired(fakeTimestampedEntry) {
t.Errorf("TTL Cache should not expire entries before ttl")
}
fakeTimestampedEntry.timestamp = expiredTime
if !policy.IsExpired(fakeTimestampedEntry) {
t.Errorf("TTL Cache should expire entries older than ttl")
}
for _, ttl = range []time.Duration{0, -1} {
policy.Ttl = ttl
if policy.IsExpired(fakeTimestampedEntry) {
t.Errorf("TTL policy should only expire entries when initialized with a ttl > 0")
}
}
}

View file

@ -1,235 +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 cache
import (
"reflect"
"testing"
"time"
)
func testFifoObjectKeyFunc(obj interface{}) (string, error) {
return obj.(testFifoObject).name, nil
}
type testFifoObject struct {
name string
val interface{}
}
func mkFifoObj(name string, val interface{}) testFifoObject {
return testFifoObject{name: name, val: val}
}
func TestFIFO_basic(t *testing.T) {
f := NewFIFO(testFifoObjectKeyFunc)
const amount = 500
go func() {
for i := 0; i < amount; i++ {
f.Add(mkFifoObj(string([]rune{'a', rune(i)}), i+1))
}
}()
go func() {
for u := uint64(0); u < amount; u++ {
f.Add(mkFifoObj(string([]rune{'b', rune(u)}), u+1))
}
}()
lastInt := int(0)
lastUint := uint64(0)
for i := 0; i < amount*2; i++ {
switch obj := f.Pop().(testFifoObject).val.(type) {
case int:
if obj <= lastInt {
t.Errorf("got %v (int) out of order, last was %v", obj, lastInt)
}
lastInt = obj
case uint64:
if obj <= lastUint {
t.Errorf("got %v (uint) out of order, last was %v", obj, lastUint)
} else {
lastUint = obj
}
default:
t.Fatalf("unexpected type %#v", obj)
}
}
}
func TestFIFO_addUpdate(t *testing.T) {
f := NewFIFO(testFifoObjectKeyFunc)
f.Add(mkFifoObj("foo", 10))
f.Update(mkFifoObj("foo", 15))
if e, a := []interface{}{mkFifoObj("foo", 15)}, f.List(); !reflect.DeepEqual(e, a) {
t.Errorf("Expected %+v, got %+v", e, a)
}
if e, a := []string{"foo"}, f.ListKeys(); !reflect.DeepEqual(e, a) {
t.Errorf("Expected %+v, got %+v", e, a)
}
got := make(chan testFifoObject, 2)
go func() {
for {
got <- f.Pop().(testFifoObject)
}
}()
first := <-got
if e, a := 15, first.val; e != a {
t.Errorf("Didn't get updated value (%v), got %v", e, a)
}
select {
case unexpected := <-got:
t.Errorf("Got second value %v", unexpected.val)
case <-time.After(50 * time.Millisecond):
}
_, exists, _ := f.Get(mkFifoObj("foo", ""))
if exists {
t.Errorf("item did not get removed")
}
}
func TestFIFO_addReplace(t *testing.T) {
f := NewFIFO(testFifoObjectKeyFunc)
f.Add(mkFifoObj("foo", 10))
f.Replace([]interface{}{mkFifoObj("foo", 15)}, "15")
got := make(chan testFifoObject, 2)
go func() {
for {
got <- f.Pop().(testFifoObject)
}
}()
first := <-got
if e, a := 15, first.val; e != a {
t.Errorf("Didn't get updated value (%v), got %v", e, a)
}
select {
case unexpected := <-got:
t.Errorf("Got second value %v", unexpected.val)
case <-time.After(50 * time.Millisecond):
}
_, exists, _ := f.Get(mkFifoObj("foo", ""))
if exists {
t.Errorf("item did not get removed")
}
}
func TestFIFO_detectLineJumpers(t *testing.T) {
f := NewFIFO(testFifoObjectKeyFunc)
f.Add(mkFifoObj("foo", 10))
f.Add(mkFifoObj("bar", 1))
f.Add(mkFifoObj("foo", 11))
f.Add(mkFifoObj("foo", 13))
f.Add(mkFifoObj("zab", 30))
if e, a := 13, f.Pop().(testFifoObject).val; a != e {
t.Fatalf("expected %d, got %d", e, a)
}
f.Add(mkFifoObj("foo", 14)) // ensure foo doesn't jump back in line
if e, a := 1, f.Pop().(testFifoObject).val; a != e {
t.Fatalf("expected %d, got %d", e, a)
}
if e, a := 30, f.Pop().(testFifoObject).val; a != e {
t.Fatalf("expected %d, got %d", e, a)
}
if e, a := 14, f.Pop().(testFifoObject).val; a != e {
t.Fatalf("expected %d, got %d", e, a)
}
}
func TestFIFO_addIfNotPresent(t *testing.T) {
f := NewFIFO(testFifoObjectKeyFunc)
f.Add(mkFifoObj("a", 1))
f.Add(mkFifoObj("b", 2))
f.AddIfNotPresent(mkFifoObj("b", 3))
f.AddIfNotPresent(mkFifoObj("c", 4))
if e, a := 3, len(f.items); a != e {
t.Fatalf("expected queue length %d, got %d", e, a)
}
expectedValues := []int{1, 2, 4}
for _, expected := range expectedValues {
if actual := f.Pop().(testFifoObject).val; actual != expected {
t.Fatalf("expected value %d, got %d", expected, actual)
}
}
}
func TestFIFO_HasSynced(t *testing.T) {
tests := []struct {
actions []func(f *FIFO)
expectedSynced bool
}{
{
actions: []func(f *FIFO){},
expectedSynced: false,
},
{
actions: []func(f *FIFO){
func(f *FIFO) { f.Add(mkFifoObj("a", 1)) },
},
expectedSynced: true,
},
{
actions: []func(f *FIFO){
func(f *FIFO) { f.Replace([]interface{}{}, "0") },
},
expectedSynced: true,
},
{
actions: []func(f *FIFO){
func(f *FIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") },
},
expectedSynced: false,
},
{
actions: []func(f *FIFO){
func(f *FIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") },
func(f *FIFO) { f.Pop() },
},
expectedSynced: false,
},
{
actions: []func(f *FIFO){
func(f *FIFO) { f.Replace([]interface{}{mkFifoObj("a", 1), mkFifoObj("b", 2)}, "0") },
func(f *FIFO) { f.Pop() },
func(f *FIFO) { f.Pop() },
},
expectedSynced: true,
},
}
for i, test := range tests {
f := NewFIFO(testFifoObjectKeyFunc)
for _, action := range test.actions {
action(f)
}
if e, a := test.expectedSynced, f.HasSynced(); a != e {
t.Errorf("test case %v failed, expected: %v , got %v", i, e, a)
}
}
}

View file

@ -1,135 +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 cache
import (
"strings"
"testing"
"k8s.io/kubernetes/pkg/api"
)
func testIndexFunc(obj interface{}) ([]string, error) {
pod := obj.(*api.Pod)
return []string{pod.Labels["foo"]}, nil
}
func TestGetIndexFuncValues(t *testing.T) {
index := NewIndexer(MetaNamespaceKeyFunc, Indexers{"testmodes": testIndexFunc})
pod1 := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "one", Labels: map[string]string{"foo": "bar"}}}
pod2 := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "two", Labels: map[string]string{"foo": "bar"}}}
pod3 := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "tre", Labels: map[string]string{"foo": "biz"}}}
index.Add(pod1)
index.Add(pod2)
index.Add(pod3)
keys := index.ListIndexFuncValues("testmodes")
if len(keys) != 2 {
t.Errorf("Expected 2 keys but got %v", len(keys))
}
for _, key := range keys {
if key != "bar" && key != "biz" {
t.Errorf("Expected only 'bar' or 'biz' but got %s", key)
}
}
}
func testUsersIndexFunc(obj interface{}) ([]string, error) {
pod := obj.(*api.Pod)
usersString := pod.Annotations["users"]
return strings.Split(usersString, ","), nil
}
func TestMultiIndexKeys(t *testing.T) {
index := NewIndexer(MetaNamespaceKeyFunc, Indexers{"byUser": testUsersIndexFunc})
pod1 := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "one", Annotations: map[string]string{"users": "ernie,bert"}}}
pod2 := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "two", Annotations: map[string]string{"users": "bert,oscar"}}}
pod3 := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "tre", Annotations: map[string]string{"users": "ernie,elmo"}}}
index.Add(pod1)
index.Add(pod2)
index.Add(pod3)
erniePods, err := index.ByIndex("byUser", "ernie")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(erniePods) != 2 {
t.Errorf("Expected 2 pods but got %v", len(erniePods))
}
bertPods, err := index.ByIndex("byUser", "bert")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(bertPods) != 2 {
t.Errorf("Expected 2 pods but got %v", len(bertPods))
}
oscarPods, err := index.ByIndex("byUser", "oscar")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(oscarPods) != 1 {
t.Errorf("Expected 1 pods but got %v", len(erniePods))
}
ernieAndBertKeys, err := index.Index("byUser", pod1)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(ernieAndBertKeys) != 3 {
t.Errorf("Expected 3 pods but got %v", len(ernieAndBertKeys))
}
index.Delete(pod3)
erniePods, err = index.ByIndex("byUser", "ernie")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(erniePods) != 1 {
t.Errorf("Expected 1 pods but got %v", len(erniePods))
}
elmoPods, err := index.ByIndex("byUser", "elmo")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(elmoPods) != 0 {
t.Errorf("Expected 0 pods but got %v", len(elmoPods))
}
obj, err := api.Scheme.DeepCopy(pod2)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
copyOfPod2 := obj.(*api.Pod)
copyOfPod2.Annotations["users"] = "oscar"
index.Update(copyOfPod2)
bertPods, err = index.ByIndex("byUser", "bert")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(bertPods) != 1 {
t.Errorf("Expected 1 pods but got %v", len(bertPods))
}
}

View file

@ -1,721 +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 cache
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/util/sets"
)
func TestStoreToNodeLister(t *testing.T) {
store := NewStore(MetaNamespaceKeyFunc)
ids := sets.NewString("foo", "bar", "baz")
for id := range ids {
store.Add(&api.Node{ObjectMeta: api.ObjectMeta{Name: id}})
}
sml := StoreToNodeLister{store}
gotNodes, err := sml.List()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
got := make([]string, len(gotNodes.Items))
for ix := range gotNodes.Items {
got[ix] = gotNodes.Items[ix].Name
}
if !ids.HasAll(got...) || len(got) != len(ids) {
t.Errorf("Expected %v, got %v", ids, got)
}
}
func TestStoreToNodeConditionLister(t *testing.T) {
store := NewStore(MetaNamespaceKeyFunc)
nodes := []*api.Node{
{
ObjectMeta: api.ObjectMeta{Name: "foo"},
Status: api.NodeStatus{
Conditions: []api.NodeCondition{
{
Type: api.NodeReady,
Status: api.ConditionTrue,
},
{
Type: api.NodeOutOfDisk,
Status: api.ConditionFalse,
},
},
},
},
{
ObjectMeta: api.ObjectMeta{Name: "bar"},
Status: api.NodeStatus{
Conditions: []api.NodeCondition{
{
Type: api.NodeOutOfDisk,
Status: api.ConditionTrue,
},
},
},
},
{
ObjectMeta: api.ObjectMeta{Name: "baz"},
Status: api.NodeStatus{
Conditions: []api.NodeCondition{
{
Type: api.NodeReady,
Status: api.ConditionFalse,
},
{
Type: api.NodeOutOfDisk,
Status: api.ConditionUnknown,
},
},
},
},
}
for _, n := range nodes {
store.Add(n)
}
predicate := func(node api.Node) bool {
for _, cond := range node.Status.Conditions {
if cond.Type == api.NodeOutOfDisk && cond.Status == api.ConditionTrue {
return false
}
}
return true
}
snl := StoreToNodeLister{store}
sncl := snl.NodeCondition(predicate)
want := sets.NewString("foo", "baz")
gotNodes, err := sncl.List()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
got := make([]string, len(gotNodes.Items))
for ix := range gotNodes.Items {
got[ix] = gotNodes.Items[ix].Name
}
if !want.HasAll(got...) || len(got) != len(want) {
t.Errorf("Expected %v, got %v", want, got)
}
}
func TestStoreToReplicationControllerLister(t *testing.T) {
store := NewStore(MetaNamespaceKeyFunc)
lister := StoreToReplicationControllerLister{store}
testCases := []struct {
inRCs []*api.ReplicationController
list func() ([]api.ReplicationController, error)
outRCNames sets.String
expectErr bool
}{
// Basic listing with all labels and no selectors
{
inRCs: []*api.ReplicationController{
{ObjectMeta: api.ObjectMeta{Name: "basic"}},
},
list: func() ([]api.ReplicationController, error) {
return lister.List()
},
outRCNames: sets.NewString("basic"),
},
// No pod labels
{
inRCs: []*api.ReplicationController{
{
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
Spec: api.ReplicationControllerSpec{
Selector: map[string]string{"foo": "baz"},
},
},
},
list: func() ([]api.ReplicationController, error) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{Name: "pod1", Namespace: "ns"},
}
return lister.GetPodControllers(pod)
},
outRCNames: sets.NewString(),
expectErr: true,
},
// No RC selectors
{
inRCs: []*api.ReplicationController{
{
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
},
},
list: func() ([]api.ReplicationController, error) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "pod1",
Namespace: "ns",
Labels: map[string]string{"foo": "bar"},
},
}
return lister.GetPodControllers(pod)
},
outRCNames: sets.NewString(),
expectErr: true,
},
// Matching labels to selectors and namespace
{
inRCs: []*api.ReplicationController{
{
ObjectMeta: api.ObjectMeta{Name: "foo"},
Spec: api.ReplicationControllerSpec{
Selector: map[string]string{"foo": "bar"},
},
},
{
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "ns"},
Spec: api.ReplicationControllerSpec{
Selector: map[string]string{"foo": "bar"},
},
},
},
list: func() ([]api.ReplicationController, error) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "pod1",
Labels: map[string]string{"foo": "bar"},
Namespace: "ns",
},
}
return lister.GetPodControllers(pod)
},
outRCNames: sets.NewString("bar"),
},
}
for _, c := range testCases {
for _, r := range c.inRCs {
store.Add(r)
}
gotControllers, err := c.list()
if err != nil && c.expectErr {
continue
} else if c.expectErr {
t.Error("Expected error, got none")
continue
} else if err != nil {
t.Errorf("Unexpected error %#v", err)
continue
}
gotNames := make([]string, len(gotControllers))
for ix := range gotControllers {
gotNames[ix] = gotControllers[ix].Name
}
if !c.outRCNames.HasAll(gotNames...) || len(gotNames) != len(c.outRCNames) {
t.Errorf("Unexpected got controllers %+v expected %+v", gotNames, c.outRCNames)
}
}
}
func TestStoreToReplicaSetLister(t *testing.T) {
store := NewStore(MetaNamespaceKeyFunc)
lister := StoreToReplicaSetLister{store}
testCases := []struct {
inRSs []*extensions.ReplicaSet
list func() ([]extensions.ReplicaSet, error)
outRSNames sets.String
expectErr bool
}{
// Basic listing with all labels and no selectors
{
inRSs: []*extensions.ReplicaSet{
{ObjectMeta: api.ObjectMeta{Name: "basic"}},
},
list: func() ([]extensions.ReplicaSet, error) {
return lister.List()
},
outRSNames: sets.NewString("basic"),
},
// No pod labels
{
inRSs: []*extensions.ReplicaSet{
{
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
Spec: extensions.ReplicaSetSpec{
Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"foo": "baz"}},
},
},
},
list: func() ([]extensions.ReplicaSet, error) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{Name: "pod1", Namespace: "ns"},
}
return lister.GetPodReplicaSets(pod)
},
outRSNames: sets.NewString(),
expectErr: true,
},
// No ReplicaSet selectors
{
inRSs: []*extensions.ReplicaSet{
{
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
},
},
list: func() ([]extensions.ReplicaSet, error) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "pod1",
Namespace: "ns",
Labels: map[string]string{"foo": "bar"},
},
}
return lister.GetPodReplicaSets(pod)
},
outRSNames: sets.NewString(),
expectErr: true,
},
// Matching labels to selectors and namespace
{
inRSs: []*extensions.ReplicaSet{
{
ObjectMeta: api.ObjectMeta{Name: "foo"},
Spec: extensions.ReplicaSetSpec{
Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
},
},
{
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "ns"},
Spec: extensions.ReplicaSetSpec{
Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
},
},
},
list: func() ([]extensions.ReplicaSet, error) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "pod1",
Labels: map[string]string{"foo": "bar"},
Namespace: "ns",
},
}
return lister.GetPodReplicaSets(pod)
},
outRSNames: sets.NewString("bar"),
},
}
for _, c := range testCases {
for _, r := range c.inRSs {
store.Add(r)
}
gotRSs, err := c.list()
if err != nil && c.expectErr {
continue
} else if c.expectErr {
t.Error("Expected error, got none")
continue
} else if err != nil {
t.Errorf("Unexpected error %#v", err)
continue
}
gotNames := make([]string, len(gotRSs))
for ix := range gotRSs {
gotNames[ix] = gotRSs[ix].Name
}
if !c.outRSNames.HasAll(gotNames...) || len(gotNames) != len(c.outRSNames) {
t.Errorf("Unexpected got ReplicaSets %+v expected %+v", gotNames, c.outRSNames)
}
}
}
func TestStoreToDaemonSetLister(t *testing.T) {
store := NewStore(MetaNamespaceKeyFunc)
lister := StoreToDaemonSetLister{store}
testCases := []struct {
inDSs []*extensions.DaemonSet
list func() ([]extensions.DaemonSet, error)
outDaemonSetNames sets.String
expectErr bool
}{
// Basic listing
{
inDSs: []*extensions.DaemonSet{
{ObjectMeta: api.ObjectMeta{Name: "basic"}},
},
list: func() ([]extensions.DaemonSet, error) {
list, err := lister.List()
return list.Items, err
},
outDaemonSetNames: sets.NewString("basic"),
},
// Listing multiple daemon sets
{
inDSs: []*extensions.DaemonSet{
{ObjectMeta: api.ObjectMeta{Name: "basic"}},
{ObjectMeta: api.ObjectMeta{Name: "complex"}},
{ObjectMeta: api.ObjectMeta{Name: "complex2"}},
},
list: func() ([]extensions.DaemonSet, error) {
list, err := lister.List()
return list.Items, err
},
outDaemonSetNames: sets.NewString("basic", "complex", "complex2"),
},
// No pod labels
{
inDSs: []*extensions.DaemonSet{
{
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
Spec: extensions.DaemonSetSpec{
Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"foo": "baz"}},
},
},
},
list: func() ([]extensions.DaemonSet, error) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{Name: "pod1", Namespace: "ns"},
}
return lister.GetPodDaemonSets(pod)
},
outDaemonSetNames: sets.NewString(),
expectErr: true,
},
// No DS selectors
{
inDSs: []*extensions.DaemonSet{
{
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
},
},
list: func() ([]extensions.DaemonSet, error) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "pod1",
Namespace: "ns",
Labels: map[string]string{"foo": "bar"},
},
}
return lister.GetPodDaemonSets(pod)
},
outDaemonSetNames: sets.NewString(),
expectErr: true,
},
// Matching labels to selectors and namespace
{
inDSs: []*extensions.DaemonSet{
{
ObjectMeta: api.ObjectMeta{Name: "foo"},
Spec: extensions.DaemonSetSpec{
Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
},
},
{
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "ns"},
Spec: extensions.DaemonSetSpec{
Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
},
},
},
list: func() ([]extensions.DaemonSet, error) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "pod1",
Labels: map[string]string{"foo": "bar"},
Namespace: "ns",
},
}
return lister.GetPodDaemonSets(pod)
},
outDaemonSetNames: sets.NewString("bar"),
},
}
for _, c := range testCases {
for _, r := range c.inDSs {
store.Add(r)
}
daemonSets, err := c.list()
if err != nil && c.expectErr {
continue
} else if c.expectErr {
t.Error("Expected error, got none")
continue
} else if err != nil {
t.Errorf("Unexpected error %#v", err)
continue
}
daemonSetNames := make([]string, len(daemonSets))
for ix := range daemonSets {
daemonSetNames[ix] = daemonSets[ix].Name
}
if !c.outDaemonSetNames.HasAll(daemonSetNames...) || len(daemonSetNames) != len(c.outDaemonSetNames) {
t.Errorf("Unexpected got controllers %+v expected %+v", daemonSetNames, c.outDaemonSetNames)
}
}
}
func TestStoreToJobLister(t *testing.T) {
store := NewStore(MetaNamespaceKeyFunc)
lister := StoreToJobLister{store}
testCases := []struct {
inJobs []*extensions.Job
list func() ([]extensions.Job, error)
outJobNames sets.String
expectErr bool
msg string
}{
// Basic listing
{
inJobs: []*extensions.Job{
{ObjectMeta: api.ObjectMeta{Name: "basic"}},
},
list: func() ([]extensions.Job, error) {
list, err := lister.List()
return list.Items, err
},
outJobNames: sets.NewString("basic"),
msg: "basic listing failed",
},
// Listing multiple jobs
{
inJobs: []*extensions.Job{
{ObjectMeta: api.ObjectMeta{Name: "basic"}},
{ObjectMeta: api.ObjectMeta{Name: "complex"}},
{ObjectMeta: api.ObjectMeta{Name: "complex2"}},
},
list: func() ([]extensions.Job, error) {
list, err := lister.List()
return list.Items, err
},
outJobNames: sets.NewString("basic", "complex", "complex2"),
msg: "listing multiple jobs failed",
},
// No pod labels
{
inJobs: []*extensions.Job{
{
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
Spec: extensions.JobSpec{
Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"foo": "baz"},
},
},
},
},
list: func() ([]extensions.Job, error) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{Name: "pod", Namespace: "ns"},
}
return lister.GetPodJobs(pod)
},
outJobNames: sets.NewString(),
expectErr: true,
msg: "listing jobs failed when pod has no labels: expected error, got none",
},
// No Job selectors
{
inJobs: []*extensions.Job{
{
ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"},
},
},
list: func() ([]extensions.Job, error) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "pod",
Namespace: "ns",
Labels: map[string]string{"foo": "bar"},
},
}
return lister.GetPodJobs(pod)
},
outJobNames: sets.NewString(),
expectErr: true,
msg: "listing jobs failed when job has no selector: expected error, got none",
},
// Matching labels to selectors and namespace
{
inJobs: []*extensions.Job{
{
ObjectMeta: api.ObjectMeta{Name: "foo"},
Spec: extensions.JobSpec{
Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"foo": "bar"},
},
},
},
{
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "ns"},
Spec: extensions.JobSpec{
Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"foo": "bar"},
},
},
},
},
list: func() ([]extensions.Job, error) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "pod",
Labels: map[string]string{"foo": "bar"},
Namespace: "ns",
},
}
return lister.GetPodJobs(pod)
},
outJobNames: sets.NewString("bar"),
msg: "listing jobs with namespace and selector failed",
},
// Matching labels to selectors and namespace, error case
{
inJobs: []*extensions.Job{
{
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "foo"},
Spec: extensions.JobSpec{
Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"foo": "bar"},
},
},
},
{
ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "bar"},
Spec: extensions.JobSpec{
Selector: &unversioned.LabelSelector{
MatchLabels: map[string]string{"foo": "bar"},
},
},
},
},
list: func() ([]extensions.Job, error) {
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "pod",
Labels: map[string]string{"foo": "bar"},
Namespace: "baz",
},
}
return lister.GetPodJobs(pod)
},
expectErr: true,
msg: "listing jobs with namespace and selector failed: expected error, got none",
},
}
for _, c := range testCases {
for _, r := range c.inJobs {
store.Add(r)
}
Jobs, err := c.list()
if err != nil && c.expectErr {
continue
} else if c.expectErr {
t.Errorf("%v", c.msg)
continue
} else if err != nil {
t.Errorf("Unexpected error %#v", err)
continue
}
JobNames := make([]string, len(Jobs))
for ix := range Jobs {
JobNames[ix] = Jobs[ix].Name
}
if !c.outJobNames.HasAll(JobNames...) || len(JobNames) != len(c.outJobNames) {
t.Errorf("%v : expected %v, got %v", c.msg, JobNames, c.outJobNames)
}
}
}
func TestStoreToPodLister(t *testing.T) {
store := NewStore(MetaNamespaceKeyFunc)
ids := []string{"foo", "bar", "baz"}
for _, id := range ids {
store.Add(&api.Pod{
ObjectMeta: api.ObjectMeta{
Name: id,
Labels: map[string]string{"name": id},
},
})
}
spl := StoreToPodLister{store}
for _, id := range ids {
got, err := spl.List(labels.Set{"name": id}.AsSelector())
if err != nil {
t.Errorf("Unexpected error: %v", err)
continue
}
if e, a := 1, len(got); e != a {
t.Errorf("Expected %v, got %v", e, a)
continue
}
if e, a := id, got[0].Name; e != a {
t.Errorf("Expected %v, got %v", e, a)
continue
}
exists, err := spl.Exists(&api.Pod{ObjectMeta: api.ObjectMeta{Name: id}})
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if !exists {
t.Errorf("exists returned false for %v", id)
}
}
exists, err := spl.Exists(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "qux"}})
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if exists {
t.Error("Unexpected pod exists")
}
}
func TestStoreToServiceLister(t *testing.T) {
store := NewStore(MetaNamespaceKeyFunc)
store.Add(&api.Service{
ObjectMeta: api.ObjectMeta{Name: "foo"},
Spec: api.ServiceSpec{
Selector: map[string]string{},
},
})
store.Add(&api.Service{ObjectMeta: api.ObjectMeta{Name: "bar"}})
ssl := StoreToServiceLister{store}
pod := &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foopod",
Labels: map[string]string{"role": "foo"},
},
}
services, err := ssl.GetPodServices(pod)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if len(services) != 1 {
t.Fatalf("Expected 1 service, got %v", len(services))
}
if e, a := "foo", services[0].Name; e != a {
t.Errorf("Expected service %q, got %q", e, a)
}
}

View file

@ -20,7 +20,7 @@ import (
"time"
"k8s.io/kubernetes/pkg/api"
client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/watch"
@ -42,7 +42,7 @@ type ListWatch struct {
// Getter interface knows how to access Get method from RESTClient.
type Getter interface {
Get() *client.Request
Get() *restclient.Request
}
// NewListWatchFromClient creates a new ListWatch from the specified client, resource, namespace and field selector.

View file

@ -1,173 +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 cache
import (
"net/http/httptest"
"net/url"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned"
client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/fields"
utiltesting "k8s.io/kubernetes/pkg/util/testing"
)
func parseSelectorOrDie(s string) fields.Selector {
selector, err := fields.ParseSelector(s)
if err != nil {
panic(err)
}
return selector
}
// buildQueryValues is a convenience function for knowing if a namespace should be in a query param or not
func buildQueryValues(query url.Values) url.Values {
v := url.Values{}
if query != nil {
for key, values := range query {
for _, value := range values {
v.Add(key, value)
}
}
}
return v
}
func buildLocation(resourcePath string, query url.Values) string {
return resourcePath + "?" + query.Encode()
}
func TestListWatchesCanList(t *testing.T) {
fieldSelectorQueryParamName := unversioned.FieldSelectorQueryParam(testapi.Default.GroupVersion().String())
table := []struct {
location string
resource string
namespace string
fieldSelector fields.Selector
}{
// Node
{
location: testapi.Default.ResourcePath("nodes", api.NamespaceAll, ""),
resource: "nodes",
namespace: api.NamespaceAll,
fieldSelector: parseSelectorOrDie(""),
},
// pod with "assigned" field selector.
{
location: buildLocation(
testapi.Default.ResourcePath("pods", api.NamespaceAll, ""),
buildQueryValues(url.Values{fieldSelectorQueryParamName: []string{"spec.host="}})),
resource: "pods",
namespace: api.NamespaceAll,
fieldSelector: fields.Set{"spec.host": ""}.AsSelector(),
},
// pod in namespace "foo"
{
location: buildLocation(
testapi.Default.ResourcePath("pods", "foo", ""),
buildQueryValues(url.Values{fieldSelectorQueryParamName: []string{"spec.host="}})),
resource: "pods",
namespace: "foo",
fieldSelector: fields.Set{"spec.host": ""}.AsSelector(),
},
}
for _, item := range table {
handler := utiltesting.FakeHandler{
StatusCode: 500,
ResponseBody: "",
T: t,
}
server := httptest.NewServer(&handler)
// TODO: Uncomment when fix #19254
// defer server.Close()
client := client.NewOrDie(&client.Config{Host: server.URL, ContentConfig: client.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}})
lw := NewListWatchFromClient(client, item.resource, item.namespace, item.fieldSelector)
// This test merely tests that the correct request is made.
lw.List(api.ListOptions{})
handler.ValidateRequest(t, item.location, "GET", nil)
}
}
func TestListWatchesCanWatch(t *testing.T) {
fieldSelectorQueryParamName := unversioned.FieldSelectorQueryParam(testapi.Default.GroupVersion().String())
table := []struct {
rv string
location string
resource string
namespace string
fieldSelector fields.Selector
}{
// Node
{
location: buildLocation(
testapi.Default.ResourcePathWithPrefix("watch", "nodes", api.NamespaceAll, ""),
buildQueryValues(url.Values{})),
rv: "",
resource: "nodes",
namespace: api.NamespaceAll,
fieldSelector: parseSelectorOrDie(""),
},
{
location: buildLocation(
testapi.Default.ResourcePathWithPrefix("watch", "nodes", api.NamespaceAll, ""),
buildQueryValues(url.Values{"resourceVersion": []string{"42"}})),
rv: "42",
resource: "nodes",
namespace: api.NamespaceAll,
fieldSelector: parseSelectorOrDie(""),
},
// pod with "assigned" field selector.
{
location: buildLocation(
testapi.Default.ResourcePathWithPrefix("watch", "pods", api.NamespaceAll, ""),
buildQueryValues(url.Values{fieldSelectorQueryParamName: []string{"spec.host="}, "resourceVersion": []string{"0"}})),
rv: "0",
resource: "pods",
namespace: api.NamespaceAll,
fieldSelector: fields.Set{"spec.host": ""}.AsSelector(),
},
// pod with namespace foo and assigned field selector
{
location: buildLocation(
testapi.Default.ResourcePathWithPrefix("watch", "pods", "foo", ""),
buildQueryValues(url.Values{fieldSelectorQueryParamName: []string{"spec.host="}, "resourceVersion": []string{"0"}})),
rv: "0",
resource: "pods",
namespace: "foo",
fieldSelector: fields.Set{"spec.host": ""}.AsSelector(),
},
}
for _, item := range table {
handler := utiltesting.FakeHandler{
StatusCode: 500,
ResponseBody: "",
T: t,
}
server := httptest.NewServer(&handler)
// TODO: Uncomment when fix #19254
// defer server.Close()
client := client.NewOrDie(&client.Config{Host: server.URL, ContentConfig: client.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}})
lw := NewListWatchFromClient(client, item.resource, item.namespace, item.fieldSelector)
// This test merely tests that the correct request is made.
lw.Watch(api.ListOptions{ResourceVersion: item.rv})
handler.ValidateRequest(t, item.location, "GET", nil)
}
}

View file

@ -1,404 +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 cache
import (
"fmt"
"math/rand"
"strconv"
"testing"
"time"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/wait"
"k8s.io/kubernetes/pkg/watch"
)
type testLW struct {
ListFunc func() (runtime.Object, error)
WatchFunc func(resourceVersion string) (watch.Interface, error)
}
func (t *testLW) List(options api.ListOptions) (runtime.Object, error) {
return t.ListFunc()
}
func (t *testLW) Watch(options api.ListOptions) (watch.Interface, error) {
return t.WatchFunc(options.ResourceVersion)
}
func TestCloseWatchChannelOnError(t *testing.T) {
r := NewReflector(&testLW{}, &api.Pod{}, NewStore(MetaNamespaceKeyFunc), 0)
pod := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "bar"}}
fw := watch.NewFake()
r.listerWatcher = &testLW{
WatchFunc: func(rv string) (watch.Interface, error) {
return fw, nil
},
ListFunc: func() (runtime.Object, error) {
return &api.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: "1"}}, nil
},
}
go r.ListAndWatch(wait.NeverStop)
fw.Error(pod)
select {
case _, ok := <-fw.ResultChan():
if ok {
t.Errorf("Watch channel left open after cancellation")
}
case <-time.After(wait.ForeverTestTimeout):
t.Errorf("the cancellation is at least %s late", wait.ForeverTestTimeout.String())
break
}
}
func TestRunUntil(t *testing.T) {
stopCh := make(chan struct{})
store := NewStore(MetaNamespaceKeyFunc)
r := NewReflector(&testLW{}, &api.Pod{}, store, 0)
fw := watch.NewFake()
r.listerWatcher = &testLW{
WatchFunc: func(rv string) (watch.Interface, error) {
return fw, nil
},
ListFunc: func() (runtime.Object, error) {
return &api.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: "1"}}, nil
},
}
r.RunUntil(stopCh)
// Synchronously add a dummy pod into the watch channel so we
// know the RunUntil go routine is in the watch handler.
fw.Add(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "bar"}})
stopCh <- struct{}{}
select {
case _, ok := <-fw.ResultChan():
if ok {
t.Errorf("Watch channel left open after stopping the watch")
}
case <-time.After(wait.ForeverTestTimeout):
t.Errorf("the cancellation is at least %s late", wait.ForeverTestTimeout.String())
break
}
}
func TestReflectorResyncChan(t *testing.T) {
s := NewStore(MetaNamespaceKeyFunc)
g := NewReflector(&testLW{}, &api.Pod{}, s, time.Millisecond)
a, _ := g.resyncChan()
b := time.After(wait.ForeverTestTimeout)
select {
case <-a:
t.Logf("got timeout as expected")
case <-b:
t.Errorf("resyncChan() is at least 99 milliseconds late??")
}
}
func BenchmarkReflectorResyncChanMany(b *testing.B) {
s := NewStore(MetaNamespaceKeyFunc)
g := NewReflector(&testLW{}, &api.Pod{}, s, 25*time.Millisecond)
// The improvement to this (calling the timer's Stop() method) makes
// this benchmark about 40% faster.
for i := 0; i < b.N; i++ {
g.resyncPeriod = time.Duration(rand.Float64() * float64(time.Millisecond) * 25)
_, stop := g.resyncChan()
stop()
}
}
func TestReflectorWatchHandlerError(t *testing.T) {
s := NewStore(MetaNamespaceKeyFunc)
g := NewReflector(&testLW{}, &api.Pod{}, s, 0)
fw := watch.NewFake()
go func() {
fw.Stop()
}()
var resumeRV string
err := g.watchHandler(fw, &resumeRV, neverExitWatch, wait.NeverStop)
if err == nil {
t.Errorf("unexpected non-error")
}
}
func TestReflectorWatchHandler(t *testing.T) {
s := NewStore(MetaNamespaceKeyFunc)
g := NewReflector(&testLW{}, &api.Pod{}, s, 0)
fw := watch.NewFake()
s.Add(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}})
s.Add(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "bar"}})
go func() {
fw.Add(&api.Service{ObjectMeta: api.ObjectMeta{Name: "rejected"}})
fw.Delete(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}})
fw.Modify(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "55"}})
fw.Add(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "32"}})
fw.Stop()
}()
var resumeRV string
err := g.watchHandler(fw, &resumeRV, neverExitWatch, wait.NeverStop)
if err != nil {
t.Errorf("unexpected error %v", err)
}
mkPod := func(id string, rv string) *api.Pod {
return &api.Pod{ObjectMeta: api.ObjectMeta{Name: id, ResourceVersion: rv}}
}
table := []struct {
Pod *api.Pod
exists bool
}{
{mkPod("foo", ""), false},
{mkPod("rejected", ""), false},
{mkPod("bar", "55"), true},
{mkPod("baz", "32"), true},
}
for _, item := range table {
obj, exists, _ := s.Get(item.Pod)
if e, a := item.exists, exists; e != a {
t.Errorf("%v: expected %v, got %v", item.Pod, e, a)
}
if !exists {
continue
}
if e, a := item.Pod.ResourceVersion, obj.(*api.Pod).ResourceVersion; e != a {
t.Errorf("%v: expected %v, got %v", item.Pod, e, a)
}
}
// RV should send the last version we see.
if e, a := "32", resumeRV; e != a {
t.Errorf("expected %v, got %v", e, a)
}
// last sync resource version should be the last version synced with store
if e, a := "32", g.LastSyncResourceVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestReflectorWatchHandlerTimeout(t *testing.T) {
s := NewStore(MetaNamespaceKeyFunc)
g := NewReflector(&testLW{}, &api.Pod{}, s, 0)
fw := watch.NewFake()
var resumeRV string
exit := make(chan time.Time, 1)
exit <- time.Now()
err := g.watchHandler(fw, &resumeRV, exit, wait.NeverStop)
if err != errorResyncRequested {
t.Errorf("expected timeout error, but got %q", err)
}
}
func TestReflectorStopWatch(t *testing.T) {
s := NewStore(MetaNamespaceKeyFunc)
g := NewReflector(&testLW{}, &api.Pod{}, s, 0)
fw := watch.NewFake()
var resumeRV string
stopWatch := make(chan struct{}, 1)
stopWatch <- struct{}{}
err := g.watchHandler(fw, &resumeRV, neverExitWatch, stopWatch)
if err != errorStopRequested {
t.Errorf("expected stop error, got %q", err)
}
}
func TestReflectorListAndWatch(t *testing.T) {
createdFakes := make(chan *watch.FakeWatcher)
// The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc
// to get called at the beginning of the watch with 1, and again with 3 when we
// inject an error.
expectedRVs := []string{"1", "3"}
lw := &testLW{
WatchFunc: func(rv string) (watch.Interface, error) {
fw := watch.NewFake()
if e, a := expectedRVs[0], rv; e != a {
t.Errorf("Expected rv %v, but got %v", e, a)
}
expectedRVs = expectedRVs[1:]
// channel is not buffered because the for loop below needs to block. But
// we don't want to block here, so report the new fake via a go routine.
go func() { createdFakes <- fw }()
return fw, nil
},
ListFunc: func() (runtime.Object, error) {
return &api.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: "1"}}, nil
},
}
s := NewFIFO(MetaNamespaceKeyFunc)
r := NewReflector(lw, &api.Pod{}, s, 0)
go r.ListAndWatch(wait.NeverStop)
ids := []string{"foo", "bar", "baz", "qux", "zoo"}
var fw *watch.FakeWatcher
for i, id := range ids {
if fw == nil {
fw = <-createdFakes
}
sendingRV := strconv.FormatUint(uint64(i+2), 10)
fw.Add(&api.Pod{ObjectMeta: api.ObjectMeta{Name: id, ResourceVersion: sendingRV}})
if sendingRV == "3" {
// Inject a failure.
fw.Stop()
fw = nil
}
}
// Verify we received the right ids with the right resource versions.
for i, id := range ids {
pod := s.Pop().(*api.Pod)
if e, a := id, pod.Name; e != a {
t.Errorf("%v: Expected %v, got %v", i, e, a)
}
if e, a := strconv.FormatUint(uint64(i+2), 10), pod.ResourceVersion; e != a {
t.Errorf("%v: Expected %v, got %v", i, e, a)
}
}
if len(expectedRVs) != 0 {
t.Error("called watchStarter an unexpected number of times")
}
}
func TestReflectorListAndWatchWithErrors(t *testing.T) {
mkPod := func(id string, rv string) *api.Pod {
return &api.Pod{ObjectMeta: api.ObjectMeta{Name: id, ResourceVersion: rv}}
}
mkList := func(rv string, pods ...*api.Pod) *api.PodList {
list := &api.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: rv}}
for _, pod := range pods {
list.Items = append(list.Items, *pod)
}
return list
}
table := []struct {
list *api.PodList
listErr error
events []watch.Event
watchErr error
}{
{
list: mkList("1"),
events: []watch.Event{
{watch.Added, mkPod("foo", "2")},
{watch.Added, mkPod("bar", "3")},
},
}, {
list: mkList("3", mkPod("foo", "2"), mkPod("bar", "3")),
events: []watch.Event{
{watch.Deleted, mkPod("foo", "4")},
{watch.Added, mkPod("qux", "5")},
},
}, {
listErr: fmt.Errorf("a list error"),
}, {
list: mkList("5", mkPod("bar", "3"), mkPod("qux", "5")),
watchErr: fmt.Errorf("a watch error"),
}, {
list: mkList("5", mkPod("bar", "3"), mkPod("qux", "5")),
events: []watch.Event{
{watch.Added, mkPod("baz", "6")},
},
}, {
list: mkList("6", mkPod("bar", "3"), mkPod("qux", "5"), mkPod("baz", "6")),
},
}
s := NewFIFO(MetaNamespaceKeyFunc)
for line, item := range table {
if item.list != nil {
// Test that the list is what currently exists in the store.
current := s.List()
checkMap := map[string]string{}
for _, item := range current {
pod := item.(*api.Pod)
checkMap[pod.Name] = pod.ResourceVersion
}
for _, pod := range item.list.Items {
if e, a := pod.ResourceVersion, checkMap[pod.Name]; e != a {
t.Errorf("%v: expected %v, got %v for pod %v", line, e, a, pod.Name)
}
}
if e, a := len(item.list.Items), len(checkMap); e != a {
t.Errorf("%v: expected %v, got %v", line, e, a)
}
}
watchRet, watchErr := item.events, item.watchErr
lw := &testLW{
WatchFunc: func(rv string) (watch.Interface, error) {
if watchErr != nil {
return nil, watchErr
}
watchErr = fmt.Errorf("second watch")
fw := watch.NewFake()
go func() {
for _, e := range watchRet {
fw.Action(e.Type, e.Object)
}
fw.Stop()
}()
return fw, nil
},
ListFunc: func() (runtime.Object, error) {
return item.list, item.listErr
},
}
r := NewReflector(lw, &api.Pod{}, s, 0)
r.ListAndWatch(wait.NeverStop)
}
}
func TestReflectorResync(t *testing.T) {
s := NewStore(MetaNamespaceKeyFunc)
currentTime := time.Time{}
iteration := 0
lw := &testLW{
WatchFunc: func(rv string) (watch.Interface, error) {
if iteration == 0 {
// Move time, but do not force resync.
currentTime = currentTime.Add(30 * time.Second)
} else if iteration == 1 {
// Move time to force resync.
currentTime = currentTime.Add(28 * time.Second)
} else if iteration >= 2 {
t.Fatalf("should have forced resync earlier")
}
iteration++
fw := watch.NewFake()
// Send something to the watcher to avoid "watch too short" errors.
go func() {
fw.Add(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: strconv.Itoa(iteration)}})
fw.Stop()
}()
return fw, nil
},
ListFunc: func() (runtime.Object, error) {
return &api.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: "0"}}, nil
},
}
resyncPeriod := time.Minute
r := NewReflector(lw, &api.Pod{}, s, resyncPeriod)
r.now = func() time.Time { return currentTime }
r.ListAndWatch(wait.NeverStop)
if iteration != 2 {
t.Errorf("exactly 2 iterations were expected, got: %v", iteration)
}
}

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 cache
import (
"testing"
"k8s.io/kubernetes/pkg/util/sets"
)
// Test public interface
func doTestStore(t *testing.T, store Store) {
mkObj := func(id string, val string) testStoreObject {
return testStoreObject{id: id, val: val}
}
store.Add(mkObj("foo", "bar"))
if item, ok, _ := store.Get(mkObj("foo", "")); !ok {
t.Errorf("didn't find inserted item")
} else {
if e, a := "bar", item.(testStoreObject).val; e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
store.Update(mkObj("foo", "baz"))
if item, ok, _ := store.Get(mkObj("foo", "")); !ok {
t.Errorf("didn't find inserted item")
} else {
if e, a := "baz", item.(testStoreObject).val; e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
store.Delete(mkObj("foo", ""))
if _, ok, _ := store.Get(mkObj("foo", "")); ok {
t.Errorf("found deleted item??")
}
// Test List.
store.Add(mkObj("a", "b"))
store.Add(mkObj("c", "d"))
store.Add(mkObj("e", "e"))
{
found := sets.String{}
for _, item := range store.List() {
found.Insert(item.(testStoreObject).val)
}
if !found.HasAll("b", "d", "e") {
t.Errorf("missing items, found: %v", found)
}
if len(found) != 3 {
t.Errorf("extra items")
}
}
// Test Replace.
store.Replace([]interface{}{
mkObj("foo", "foo"),
mkObj("bar", "bar"),
}, "0")
{
found := sets.String{}
for _, item := range store.List() {
found.Insert(item.(testStoreObject).val)
}
if !found.HasAll("foo", "bar") {
t.Errorf("missing items")
}
if len(found) != 2 {
t.Errorf("extra items")
}
}
}
// Test public interface
func doTestIndex(t *testing.T, indexer Indexer) {
mkObj := func(id string, val string) testStoreObject {
return testStoreObject{id: id, val: val}
}
// Test Index
expected := map[string]sets.String{}
expected["b"] = sets.NewString("a", "c")
expected["f"] = sets.NewString("e")
expected["h"] = sets.NewString("g")
indexer.Add(mkObj("a", "b"))
indexer.Add(mkObj("c", "b"))
indexer.Add(mkObj("e", "f"))
indexer.Add(mkObj("g", "h"))
{
for k, v := range expected {
found := sets.String{}
indexResults, err := indexer.Index("by_val", mkObj("", k))
if err != nil {
t.Errorf("Unexpected error %v", err)
}
for _, item := range indexResults {
found.Insert(item.(testStoreObject).id)
}
items := v.List()
if !found.HasAll(items...) {
t.Errorf("missing items, index %s, expected %v but found %v", k, items, found.List())
}
}
}
}
func testStoreKeyFunc(obj interface{}) (string, error) {
return obj.(testStoreObject).id, nil
}
func testStoreIndexFunc(obj interface{}) ([]string, error) {
return []string{obj.(testStoreObject).val}, nil
}
func testStoreIndexers() Indexers {
indexers := Indexers{}
indexers["by_val"] = testStoreIndexFunc
return indexers
}
type testStoreObject struct {
id string
val string
}
func TestCache(t *testing.T) {
doTestStore(t, NewStore(testStoreKeyFunc))
}
func TestFIFOCache(t *testing.T) {
doTestStore(t, NewFIFO(testStoreKeyFunc))
}
func TestUndeltaStore(t *testing.T) {
nop := func([]interface{}) {}
doTestStore(t, NewUndeltaStore(nop, testStoreKeyFunc))
}
func TestIndex(t *testing.T) {
doTestIndex(t, NewIndexer(testStoreKeyFunc, testStoreIndexers()))
}

View file

@ -1,131 +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 cache
import (
"reflect"
"testing"
)
// store_test.go checks that UndeltaStore conforms to the Store interface
// behavior. This test just tests that it calls the push func in addition.
type testUndeltaObject struct {
name string
val interface{}
}
func testUndeltaKeyFunc(obj interface{}) (string, error) {
return obj.(testUndeltaObject).name, nil
}
/*
var (
o1 interface{} = t{1}
o2 interface{} = t{2}
l1 []interface{} = []interface{}{t{1}}
)
*/
func TestUpdateCallsPush(t *testing.T) {
mkObj := func(name string, val interface{}) testUndeltaObject {
return testUndeltaObject{name: name, val: val}
}
var got []interface{}
var callcount int = 0
push := func(m []interface{}) {
callcount++
got = m
}
u := NewUndeltaStore(push, testUndeltaKeyFunc)
u.Add(mkObj("a", 2))
u.Update(mkObj("a", 1))
if callcount != 2 {
t.Errorf("Expected 2 calls, got %d", callcount)
}
l := []interface{}{mkObj("a", 1)}
if !reflect.DeepEqual(l, got) {
t.Errorf("Expected %#v, Got %#v", l, got)
}
}
func TestDeleteCallsPush(t *testing.T) {
mkObj := func(name string, val interface{}) testUndeltaObject {
return testUndeltaObject{name: name, val: val}
}
var got []interface{}
var callcount int = 0
push := func(m []interface{}) {
callcount++
got = m
}
u := NewUndeltaStore(push, testUndeltaKeyFunc)
u.Add(mkObj("a", 2))
u.Delete(mkObj("a", ""))
if callcount != 2 {
t.Errorf("Expected 2 calls, got %d", callcount)
}
expected := []interface{}{}
if !reflect.DeepEqual(expected, got) {
t.Errorf("Expected %#v, Got %#v", expected, got)
}
}
func TestReadsDoNotCallPush(t *testing.T) {
push := func(m []interface{}) {
t.Errorf("Unexpected call to push!")
}
u := NewUndeltaStore(push, testUndeltaKeyFunc)
// These should not call push.
_ = u.List()
_, _, _ = u.Get(testUndeltaObject{"a", ""})
}
func TestReplaceCallsPush(t *testing.T) {
mkObj := func(name string, val interface{}) testUndeltaObject {
return testUndeltaObject{name: name, val: val}
}
var got []interface{}
var callcount int = 0
push := func(m []interface{}) {
callcount++
got = m
}
u := NewUndeltaStore(push, testUndeltaKeyFunc)
m := []interface{}{mkObj("a", 1)}
u.Replace(m, "0")
if callcount != 1 {
t.Errorf("Expected 1 calls, got %d", callcount)
}
expected := []interface{}{mkObj("a", 1)}
if !reflect.DeepEqual(expected, got) {
t.Errorf("Expected %#v, Got %#v", expected, got)
}
}

View file

@ -18,13 +18,14 @@ package internalclientset
import (
"github.com/golang/glog"
restclient "k8s.io/kubernetes/pkg/client/restclient"
discovery "k8s.io/kubernetes/pkg/client/typed/discovery"
unversionedcore "k8s.io/kubernetes/pkg/client/typed/generated/core/unversioned"
unversionedextensions "k8s.io/kubernetes/pkg/client/typed/generated/extensions/unversioned"
unversioned "k8s.io/kubernetes/pkg/client/unversioned"
)
type Interface interface {
Discovery() unversioned.DiscoveryInterface
Discovery() discovery.DiscoveryInterface
Core() unversionedcore.CoreInterface
Extensions() unversionedextensions.ExtensionsInterface
}
@ -32,7 +33,7 @@ type Interface interface {
// Clientset contains the clients for groups. Each group has exactly one
// version included in a Clientset.
type Clientset struct {
*unversioned.DiscoveryClient
*discovery.DiscoveryClient
*unversionedcore.CoreClient
*unversionedextensions.ExtensionsClient
}
@ -48,12 +49,12 @@ func (c *Clientset) Extensions() unversionedextensions.ExtensionsInterface {
}
// Discovery retrieves the DiscoveryClient
func (c *Clientset) Discovery() unversioned.DiscoveryInterface {
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
return c.DiscoveryClient
}
// NewForConfig creates a new Clientset for the given config.
func NewForConfig(c *unversioned.Config) (*Clientset, error) {
func NewForConfig(c *restclient.Config) (*Clientset, error) {
var clientset Clientset
var err error
clientset.CoreClient, err = unversionedcore.NewForConfig(c)
@ -65,7 +66,7 @@ func NewForConfig(c *unversioned.Config) (*Clientset, error) {
return &clientset, err
}
clientset.DiscoveryClient, err = unversioned.NewDiscoveryClientForConfig(c)
clientset.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(c)
if err != nil {
glog.Errorf("failed to create the DiscoveryClient: %v", err)
}
@ -74,21 +75,21 @@ func NewForConfig(c *unversioned.Config) (*Clientset, error) {
// NewForConfigOrDie creates a new Clientset for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *unversioned.Config) *Clientset {
func NewForConfigOrDie(c *restclient.Config) *Clientset {
var clientset Clientset
clientset.CoreClient = unversionedcore.NewForConfigOrDie(c)
clientset.ExtensionsClient = unversionedextensions.NewForConfigOrDie(c)
clientset.DiscoveryClient = unversioned.NewDiscoveryClientForConfigOrDie(c)
clientset.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
return &clientset
}
// New creates a new Clientset for the given RESTClient.
func New(c *unversioned.RESTClient) *Clientset {
func New(c *restclient.RESTClient) *Clientset {
var clientset Clientset
clientset.CoreClient = unversionedcore.New(c)
clientset.ExtensionsClient = unversionedextensions.New(c)
clientset.DiscoveryClient = unversioned.NewDiscoveryClient(c)
clientset.DiscoveryClient = discovery.NewDiscoveryClient(c)
return &clientset
}

View file

@ -17,6 +17,7 @@ limitations under the License.
package internalclientset
import (
"k8s.io/kubernetes/pkg/client/typed/discovery"
unversionedcore "k8s.io/kubernetes/pkg/client/typed/generated/core/unversioned"
unversionedextensions "k8s.io/kubernetes/pkg/client/typed/generated/extensions/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned"
@ -38,5 +39,11 @@ func FromUnversionedClient(c *unversioned.Client) *Clientset {
clientset.ExtensionsClient = unversionedextensions.New(nil)
}
if c != nil && c.DiscoveryClient != nil {
clientset.DiscoveryClient = discovery.NewDiscoveryClient(c.DiscoveryClient.RESTClient)
} else {
clientset.DiscoveryClient = discovery.NewDiscoveryClient(nil)
}
return &clientset
}

View file

@ -1,70 +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 fake
import (
"k8s.io/kubernetes/pkg/api"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/testing/core"
unversionedcore "k8s.io/kubernetes/pkg/client/typed/generated/core/unversioned"
fakeunversionedcore "k8s.io/kubernetes/pkg/client/typed/generated/core/unversioned/fake"
unversionedextensions "k8s.io/kubernetes/pkg/client/typed/generated/extensions/unversioned"
fakeunversionedextensions "k8s.io/kubernetes/pkg/client/typed/generated/extensions/unversioned/fake"
"k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/watch"
)
// Clientset returns a clientset that will respond with the provided objects
func NewSimpleClientset(objects ...runtime.Object) *Clientset {
o := core.NewObjects(api.Scheme, api.Codecs.UniversalDecoder())
for _, obj := range objects {
if err := o.Add(obj); err != nil {
panic(err)
}
}
fakePtr := core.Fake{}
fakePtr.AddReactor("*", "*", core.ObjectReaction(o, api.RESTMapper))
fakePtr.AddWatchReactor("*", core.DefaultWatchReactor(watch.NewFake(), nil))
return &Clientset{fakePtr}
}
// Clientset implements clientset.Interface. Meant to be embedded into a
// struct to get a default implementation. This makes faking out just the method
// you want to test easier.
type Clientset struct {
core.Fake
}
func (c *Clientset) Discovery() unversioned.DiscoveryInterface {
return &FakeDiscovery{&c.Fake}
}
var _ clientset.Interface = &Clientset{}
// Core retrieves the CoreClient
func (c *Clientset) Core() unversionedcore.CoreInterface {
return &fakeunversionedcore.FakeCore{&c.Fake}
}
// Extensions retrieves the ExtensionsClient
func (c *Clientset) Extensions() unversionedextensions.ExtensionsInterface {
return &fakeunversionedextensions.FakeExtensions{&c.Fake}
}

View file

@ -1,76 +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.
*/
// TODO: the fake discovery client should live in pkg/client/discovery/, rather
// than being copied in every fake clientset.
package fake
import (
"github.com/emicklei/go-restful/swagger"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/client/testing/core"
"k8s.io/kubernetes/pkg/version"
)
type FakeDiscovery struct {
*core.Fake
}
func (c *FakeDiscovery) ServerResourcesForGroupVersion(groupVersion string) (*unversioned.APIResourceList, error) {
action := core.ActionImpl{
Verb: "get",
Resource: "resource",
}
c.Invokes(action, nil)
return c.Resources[groupVersion], nil
}
func (c *FakeDiscovery) ServerResources() (map[string]*unversioned.APIResourceList, error) {
action := core.ActionImpl{
Verb: "get",
Resource: "resource",
}
c.Invokes(action, nil)
return c.Resources, nil
}
func (c *FakeDiscovery) ServerGroups() (*unversioned.APIGroupList, error) {
return nil, nil
}
func (c *FakeDiscovery) ServerVersion() (*version.Info, error) {
action := core.ActionImpl{}
action.Verb = "get"
action.Resource = "version"
c.Invokes(action, nil)
versionInfo := version.Get()
return &versionInfo, nil
}
func (c *FakeDiscovery) SwaggerSchema(version unversioned.GroupVersion) (*swagger.ApiDeclaration, error) {
action := core.ActionImpl{}
action.Verb = "get"
if version == v1.SchemeGroupVersion {
action.Resource = "/swaggerapi/api/" + version.Version
} else {
action.Resource = "/swaggerapi/apis/" + version.Group + "/" + version.Version
}
c.Invokes(action, nil)
return &swagger.ApiDeclaration{}, nil
}

View file

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

View file

@ -1,885 +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 record
import (
"encoding/json"
"fmt"
"math/rand"
"strconv"
"testing"
"time"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
client "k8s.io/kubernetes/pkg/client/unversioned"
k8sruntime "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/strategicpatch"
)
func init() {
// Don't bother sleeping between retries.
sleepDuration = 0
}
type testEventSink struct {
OnCreate func(e *api.Event) (*api.Event, error)
OnUpdate func(e *api.Event) (*api.Event, error)
OnPatch func(e *api.Event, p []byte) (*api.Event, error)
}
// CreateEvent records the event for testing.
func (t *testEventSink) Create(e *api.Event) (*api.Event, error) {
if t.OnCreate != nil {
return t.OnCreate(e)
}
return e, nil
}
// UpdateEvent records the event for testing.
func (t *testEventSink) Update(e *api.Event) (*api.Event, error) {
if t.OnUpdate != nil {
return t.OnUpdate(e)
}
return e, nil
}
// PatchEvent records the event for testing.
func (t *testEventSink) Patch(e *api.Event, p []byte) (*api.Event, error) {
if t.OnPatch != nil {
return t.OnPatch(e, p)
}
return e, nil
}
type OnCreateFunc func(*api.Event) (*api.Event, error)
func OnCreateFactory(testCache map[string]*api.Event, createEvent chan<- *api.Event) OnCreateFunc {
return func(event *api.Event) (*api.Event, error) {
testCache[getEventKey(event)] = event
createEvent <- event
return event, nil
}
}
type OnPatchFunc func(*api.Event, []byte) (*api.Event, error)
func OnPatchFactory(testCache map[string]*api.Event, patchEvent chan<- *api.Event) OnPatchFunc {
return func(event *api.Event, patch []byte) (*api.Event, error) {
cachedEvent, found := testCache[getEventKey(event)]
if !found {
return nil, fmt.Errorf("unexpected error: couldn't find Event in testCache.")
}
originalData, err := json.Marshal(cachedEvent)
if err != nil {
return nil, fmt.Errorf("unexpected error: %v", err)
}
patched, err := strategicpatch.StrategicMergePatch(originalData, patch, event)
if err != nil {
return nil, fmt.Errorf("unexpected error: %v", err)
}
patchedObj := &api.Event{}
err = json.Unmarshal(patched, patchedObj)
if err != nil {
return nil, fmt.Errorf("unexpected error: %v", err)
}
patchEvent <- patchedObj
return patchedObj, nil
}
}
func TestEventf(t *testing.T) {
testPod := &api.Pod{
ObjectMeta: api.ObjectMeta{
SelfLink: "/api/version/pods/foo",
Name: "foo",
Namespace: "baz",
UID: "bar",
},
}
testPod2 := &api.Pod{
ObjectMeta: api.ObjectMeta{
SelfLink: "/api/version/pods/foo",
Name: "foo",
Namespace: "baz",
UID: "differentUid",
},
}
testRef, err := api.GetPartialReference(testPod, "spec.containers[2]")
testRef2, err := api.GetPartialReference(testPod2, "spec.containers[3]")
if err != nil {
t.Fatal(err)
}
table := []struct {
obj k8sruntime.Object
eventtype string
reason string
messageFmt string
elements []interface{}
expect *api.Event
expectLog string
expectUpdate bool
}{
{
obj: testRef,
eventtype: api.EventTypeNormal,
reason: "Started",
messageFmt: "some verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "bar",
APIVersion: "version",
FieldPath: "spec.containers[2]",
},
Reason: "Started",
Message: "some verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 1,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`,
expectUpdate: false,
},
{
obj: testPod,
eventtype: api.EventTypeNormal,
reason: "Killed",
messageFmt: "some other verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "bar",
APIVersion: "version",
},
Reason: "Killed",
Message: "some other verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 1,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:""}): type: 'Normal' reason: 'Killed' some other verbose message: 1`,
expectUpdate: false,
},
{
obj: testRef,
eventtype: api.EventTypeNormal,
reason: "Started",
messageFmt: "some verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "bar",
APIVersion: "version",
FieldPath: "spec.containers[2]",
},
Reason: "Started",
Message: "some verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 2,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`,
expectUpdate: true,
},
{
obj: testRef2,
eventtype: api.EventTypeNormal,
reason: "Started",
messageFmt: "some verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "differentUid",
APIVersion: "version",
FieldPath: "spec.containers[3]",
},
Reason: "Started",
Message: "some verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 1,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): type: 'Normal' reason: 'Started' some verbose message: 1`,
expectUpdate: false,
},
{
obj: testRef,
eventtype: api.EventTypeNormal,
reason: "Started",
messageFmt: "some verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "bar",
APIVersion: "version",
FieldPath: "spec.containers[2]",
},
Reason: "Started",
Message: "some verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 3,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`,
expectUpdate: true,
},
{
obj: testRef2,
eventtype: api.EventTypeNormal,
reason: "Stopped",
messageFmt: "some verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "differentUid",
APIVersion: "version",
FieldPath: "spec.containers[3]",
},
Reason: "Stopped",
Message: "some verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 1,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): type: 'Normal' reason: 'Stopped' some verbose message: 1`,
expectUpdate: false,
},
{
obj: testRef2,
eventtype: api.EventTypeNormal,
reason: "Stopped",
messageFmt: "some verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "differentUid",
APIVersion: "version",
FieldPath: "spec.containers[3]",
},
Reason: "Stopped",
Message: "some verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 2,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): type: 'Normal' reason: 'Stopped' some verbose message: 1`,
expectUpdate: true,
},
}
testCache := map[string]*api.Event{}
logCalled := make(chan struct{})
createEvent := make(chan *api.Event)
updateEvent := make(chan *api.Event)
patchEvent := make(chan *api.Event)
testEvents := testEventSink{
OnCreate: OnCreateFactory(testCache, createEvent),
OnUpdate: func(event *api.Event) (*api.Event, error) {
updateEvent <- event
return event, nil
},
OnPatch: OnPatchFactory(testCache, patchEvent),
}
eventBroadcaster := NewBroadcaster()
sinkWatcher := eventBroadcaster.StartRecordingToSink(&testEvents)
clock := util.NewFakeClock(time.Now())
recorder := recorderWithFakeClock(api.EventSource{Component: "eventTest"}, eventBroadcaster, clock)
for index, item := range table {
clock.Step(1 * time.Second)
logWatcher1 := eventBroadcaster.StartLogging(t.Logf) // Prove that it is useful
logWatcher2 := eventBroadcaster.StartLogging(func(formatter string, args ...interface{}) {
if e, a := item.expectLog, fmt.Sprintf(formatter, args...); e != a {
t.Errorf("Expected '%v', got '%v'", e, a)
}
logCalled <- struct{}{}
})
recorder.Eventf(item.obj, item.eventtype, item.reason, item.messageFmt, item.elements...)
<-logCalled
// validate event
if item.expectUpdate {
actualEvent := <-patchEvent
validateEvent(string(index), actualEvent, item.expect, t)
} else {
actualEvent := <-createEvent
validateEvent(string(index), actualEvent, item.expect, t)
}
logWatcher1.Stop()
logWatcher2.Stop()
}
sinkWatcher.Stop()
}
func recorderWithFakeClock(eventSource api.EventSource, eventBroadcaster EventBroadcaster, clock util.Clock) EventRecorder {
return &recorderImpl{eventSource, eventBroadcaster.(*eventBroadcasterImpl).Broadcaster, clock}
}
func TestWriteEventError(t *testing.T) {
type entry struct {
timesToSendError int
attemptsWanted int
err error
}
table := map[string]*entry{
"giveUp1": {
timesToSendError: 1000,
attemptsWanted: 1,
err: &client.RequestConstructionError{},
},
"giveUp2": {
timesToSendError: 1000,
attemptsWanted: 1,
err: &errors.StatusError{},
},
"retry1": {
timesToSendError: 1000,
attemptsWanted: 12,
err: &errors.UnexpectedObjectError{},
},
"retry2": {
timesToSendError: 1000,
attemptsWanted: 12,
err: fmt.Errorf("A weird error"),
},
"succeedEventually": {
timesToSendError: 2,
attemptsWanted: 2,
err: fmt.Errorf("A weird error"),
},
}
eventCorrelator := NewEventCorrelator(util.RealClock{})
randGen := rand.New(rand.NewSource(time.Now().UnixNano()))
for caseName, ent := range table {
attempts := 0
sink := &testEventSink{
OnCreate: func(event *api.Event) (*api.Event, error) {
attempts++
if attempts < ent.timesToSendError {
return nil, ent.err
}
return event, nil
},
}
ev := &api.Event{}
recordToSink(sink, ev, eventCorrelator, randGen)
if attempts != ent.attemptsWanted {
t.Errorf("case %v: wanted %d, got %d attempts", caseName, ent.attemptsWanted, attempts)
}
}
}
func TestLotsOfEvents(t *testing.T) {
recorderCalled := make(chan struct{})
loggerCalled := make(chan struct{})
// Fail each event a few times to ensure there's some load on the tested code.
var counts [1000]int
testEvents := testEventSink{
OnCreate: func(event *api.Event) (*api.Event, error) {
num, err := strconv.Atoi(event.Message)
if err != nil {
t.Error(err)
return event, nil
}
counts[num]++
if counts[num] < 5 {
return nil, fmt.Errorf("fake error")
}
recorderCalled <- struct{}{}
return event, nil
},
}
eventBroadcaster := NewBroadcaster()
sinkWatcher := eventBroadcaster.StartRecordingToSink(&testEvents)
logWatcher := eventBroadcaster.StartLogging(func(formatter string, args ...interface{}) {
loggerCalled <- struct{}{}
})
recorder := eventBroadcaster.NewRecorder(api.EventSource{Component: "eventTest"})
ref := &api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "bar",
APIVersion: "version",
}
for i := 0; i < maxQueuedEvents; i++ {
// we need to vary the reason to prevent aggregation
go recorder.Eventf(ref, api.EventTypeNormal, "Reason-"+string(i), strconv.Itoa(i))
}
// Make sure no events were dropped by either of the listeners.
for i := 0; i < maxQueuedEvents; i++ {
<-recorderCalled
<-loggerCalled
}
// Make sure that every event was attempted 5 times
for i := 0; i < maxQueuedEvents; i++ {
if counts[i] < 5 {
t.Errorf("Only attempted to record event '%d' %d times.", i, counts[i])
}
}
sinkWatcher.Stop()
logWatcher.Stop()
}
func TestEventfNoNamespace(t *testing.T) {
testPod := &api.Pod{
ObjectMeta: api.ObjectMeta{
SelfLink: "/api/version/pods/foo",
Name: "foo",
UID: "bar",
},
}
testRef, err := api.GetPartialReference(testPod, "spec.containers[2]")
if err != nil {
t.Fatal(err)
}
table := []struct {
obj k8sruntime.Object
eventtype string
reason string
messageFmt string
elements []interface{}
expect *api.Event
expectLog string
expectUpdate bool
}{
{
obj: testRef,
eventtype: api.EventTypeNormal,
reason: "Started",
messageFmt: "some verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "default",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "",
UID: "bar",
APIVersion: "version",
FieldPath: "spec.containers[2]",
},
Reason: "Started",
Message: "some verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 1,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`,
expectUpdate: false,
},
}
testCache := map[string]*api.Event{}
logCalled := make(chan struct{})
createEvent := make(chan *api.Event)
updateEvent := make(chan *api.Event)
patchEvent := make(chan *api.Event)
testEvents := testEventSink{
OnCreate: OnCreateFactory(testCache, createEvent),
OnUpdate: func(event *api.Event) (*api.Event, error) {
updateEvent <- event
return event, nil
},
OnPatch: OnPatchFactory(testCache, patchEvent),
}
eventBroadcaster := NewBroadcaster()
sinkWatcher := eventBroadcaster.StartRecordingToSink(&testEvents)
clock := util.NewFakeClock(time.Now())
recorder := recorderWithFakeClock(api.EventSource{Component: "eventTest"}, eventBroadcaster, clock)
for index, item := range table {
clock.Step(1 * time.Second)
logWatcher1 := eventBroadcaster.StartLogging(t.Logf) // Prove that it is useful
logWatcher2 := eventBroadcaster.StartLogging(func(formatter string, args ...interface{}) {
if e, a := item.expectLog, fmt.Sprintf(formatter, args...); e != a {
t.Errorf("Expected '%v', got '%v'", e, a)
}
logCalled <- struct{}{}
})
recorder.Eventf(item.obj, item.eventtype, item.reason, item.messageFmt, item.elements...)
<-logCalled
// validate event
if item.expectUpdate {
actualEvent := <-patchEvent
validateEvent(string(index), actualEvent, item.expect, t)
} else {
actualEvent := <-createEvent
validateEvent(string(index), actualEvent, item.expect, t)
}
logWatcher1.Stop()
logWatcher2.Stop()
}
sinkWatcher.Stop()
}
func TestMultiSinkCache(t *testing.T) {
testPod := &api.Pod{
ObjectMeta: api.ObjectMeta{
SelfLink: "/api/version/pods/foo",
Name: "foo",
Namespace: "baz",
UID: "bar",
},
}
testPod2 := &api.Pod{
ObjectMeta: api.ObjectMeta{
SelfLink: "/api/version/pods/foo",
Name: "foo",
Namespace: "baz",
UID: "differentUid",
},
}
testRef, err := api.GetPartialReference(testPod, "spec.containers[2]")
testRef2, err := api.GetPartialReference(testPod2, "spec.containers[3]")
if err != nil {
t.Fatal(err)
}
table := []struct {
obj k8sruntime.Object
eventtype string
reason string
messageFmt string
elements []interface{}
expect *api.Event
expectLog string
expectUpdate bool
}{
{
obj: testRef,
eventtype: api.EventTypeNormal,
reason: "Started",
messageFmt: "some verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "bar",
APIVersion: "version",
FieldPath: "spec.containers[2]",
},
Reason: "Started",
Message: "some verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 1,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`,
expectUpdate: false,
},
{
obj: testPod,
eventtype: api.EventTypeNormal,
reason: "Killed",
messageFmt: "some other verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "bar",
APIVersion: "version",
},
Reason: "Killed",
Message: "some other verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 1,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:""}): type: 'Normal' reason: 'Killed' some other verbose message: 1`,
expectUpdate: false,
},
{
obj: testRef,
eventtype: api.EventTypeNormal,
reason: "Started",
messageFmt: "some verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "bar",
APIVersion: "version",
FieldPath: "spec.containers[2]",
},
Reason: "Started",
Message: "some verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 2,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`,
expectUpdate: true,
},
{
obj: testRef2,
eventtype: api.EventTypeNormal,
reason: "Started",
messageFmt: "some verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "differentUid",
APIVersion: "version",
FieldPath: "spec.containers[3]",
},
Reason: "Started",
Message: "some verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 1,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): type: 'Normal' reason: 'Started' some verbose message: 1`,
expectUpdate: false,
},
{
obj: testRef,
eventtype: api.EventTypeNormal,
reason: "Started",
messageFmt: "some verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "bar",
APIVersion: "version",
FieldPath: "spec.containers[2]",
},
Reason: "Started",
Message: "some verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 3,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"bar", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[2]"}): type: 'Normal' reason: 'Started' some verbose message: 1`,
expectUpdate: true,
},
{
obj: testRef2,
eventtype: api.EventTypeNormal,
reason: "Stopped",
messageFmt: "some verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "differentUid",
APIVersion: "version",
FieldPath: "spec.containers[3]",
},
Reason: "Stopped",
Message: "some verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 1,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): type: 'Normal' reason: 'Stopped' some verbose message: 1`,
expectUpdate: false,
},
{
obj: testRef2,
eventtype: api.EventTypeNormal,
reason: "Stopped",
messageFmt: "some verbose message: %v",
elements: []interface{}{1},
expect: &api.Event{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
},
InvolvedObject: api.ObjectReference{
Kind: "Pod",
Name: "foo",
Namespace: "baz",
UID: "differentUid",
APIVersion: "version",
FieldPath: "spec.containers[3]",
},
Reason: "Stopped",
Message: "some verbose message: 1",
Source: api.EventSource{Component: "eventTest"},
Count: 2,
Type: api.EventTypeNormal,
},
expectLog: `Event(api.ObjectReference{Kind:"Pod", Namespace:"baz", Name:"foo", UID:"differentUid", APIVersion:"version", ResourceVersion:"", FieldPath:"spec.containers[3]"}): type: 'Normal' reason: 'Stopped' some verbose message: 1`,
expectUpdate: true,
},
}
testCache := map[string]*api.Event{}
createEvent := make(chan *api.Event)
updateEvent := make(chan *api.Event)
patchEvent := make(chan *api.Event)
testEvents := testEventSink{
OnCreate: OnCreateFactory(testCache, createEvent),
OnUpdate: func(event *api.Event) (*api.Event, error) {
updateEvent <- event
return event, nil
},
OnPatch: OnPatchFactory(testCache, patchEvent),
}
testCache2 := map[string]*api.Event{}
createEvent2 := make(chan *api.Event)
updateEvent2 := make(chan *api.Event)
patchEvent2 := make(chan *api.Event)
testEvents2 := testEventSink{
OnCreate: OnCreateFactory(testCache2, createEvent2),
OnUpdate: func(event *api.Event) (*api.Event, error) {
updateEvent2 <- event
return event, nil
},
OnPatch: OnPatchFactory(testCache2, patchEvent2),
}
eventBroadcaster := NewBroadcaster()
clock := util.NewFakeClock(time.Now())
recorder := recorderWithFakeClock(api.EventSource{Component: "eventTest"}, eventBroadcaster, clock)
sinkWatcher := eventBroadcaster.StartRecordingToSink(&testEvents)
for index, item := range table {
clock.Step(1 * time.Second)
recorder.Eventf(item.obj, item.eventtype, item.reason, item.messageFmt, item.elements...)
// validate event
if item.expectUpdate {
actualEvent := <-patchEvent
validateEvent(string(index), actualEvent, item.expect, t)
} else {
actualEvent := <-createEvent
validateEvent(string(index), actualEvent, item.expect, t)
}
}
// Another StartRecordingToSink call should start to record events with new clean cache.
sinkWatcher2 := eventBroadcaster.StartRecordingToSink(&testEvents2)
for index, item := range table {
clock.Step(1 * time.Second)
recorder.Eventf(item.obj, item.eventtype, item.reason, item.messageFmt, item.elements...)
// validate event
if item.expectUpdate {
actualEvent := <-patchEvent2
validateEvent(string(index), actualEvent, item.expect, t)
} else {
actualEvent := <-createEvent2
validateEvent(string(index), actualEvent, item.expect, t)
}
}
sinkWatcher.Stop()
sinkWatcher2.Stop()
}

View file

@ -1,253 +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 record
import (
"reflect"
"strings"
"testing"
"time"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/util"
)
func makeObjectReference(kind, name, namespace string) api.ObjectReference {
return api.ObjectReference{
Kind: kind,
Name: name,
Namespace: namespace,
UID: "C934D34AFB20242",
APIVersion: "version",
}
}
func makeEvent(reason, message string, involvedObject api.ObjectReference) api.Event {
eventTime := unversioned.Now()
event := api.Event{
Reason: reason,
Message: message,
InvolvedObject: involvedObject,
Source: api.EventSource{
Component: "kubelet",
Host: "kublet.node1",
},
Count: 1,
FirstTimestamp: eventTime,
LastTimestamp: eventTime,
Type: api.EventTypeNormal,
}
return event
}
func makeEvents(num int, template api.Event) []api.Event {
events := []api.Event{}
for i := 0; i < num; i++ {
events = append(events, template)
}
return events
}
func makeUniqueEvents(num int) []api.Event {
events := []api.Event{}
kind := "Pod"
for i := 0; i < num; i++ {
reason := strings.Join([]string{"reason", string(i)}, "-")
message := strings.Join([]string{"message", string(i)}, "-")
name := strings.Join([]string{"pod", string(i)}, "-")
namespace := strings.Join([]string{"ns", string(i)}, "-")
involvedObject := makeObjectReference(kind, name, namespace)
events = append(events, makeEvent(reason, message, involvedObject))
}
return events
}
func makeSimilarEvents(num int, template api.Event, messagePrefix string) []api.Event {
events := makeEvents(num, template)
for i := range events {
events[i].Message = strings.Join([]string{messagePrefix, string(i), events[i].Message}, "-")
}
return events
}
func setCount(event api.Event, count int) api.Event {
event.Count = count
return event
}
func validateEvent(messagePrefix string, actualEvent *api.Event, expectedEvent *api.Event, t *testing.T) (*api.Event, error) {
recvEvent := *actualEvent
expectCompression := expectedEvent.Count > 1
t.Logf("%v - expectedEvent.Count is %d\n", messagePrefix, expectedEvent.Count)
// Just check that the timestamp was set.
if recvEvent.FirstTimestamp.IsZero() || recvEvent.LastTimestamp.IsZero() {
t.Errorf("%v - timestamp wasn't set: %#v", messagePrefix, recvEvent)
}
actualFirstTimestamp := recvEvent.FirstTimestamp
actualLastTimestamp := recvEvent.LastTimestamp
if actualFirstTimestamp.Equal(actualLastTimestamp) {
if expectCompression {
t.Errorf("%v - FirstTimestamp (%q) and LastTimestamp (%q) must be different to indicate event compression happened, but were the same. Actual Event: %#v", messagePrefix, actualFirstTimestamp, actualLastTimestamp, recvEvent)
}
} else {
if expectedEvent.Count == 1 {
t.Errorf("%v - FirstTimestamp (%q) and LastTimestamp (%q) must be equal to indicate only one occurrence of the event, but were different. Actual Event: %#v", messagePrefix, actualFirstTimestamp, actualLastTimestamp, recvEvent)
}
}
// Temp clear time stamps for comparison because actual values don't matter for comparison
recvEvent.FirstTimestamp = expectedEvent.FirstTimestamp
recvEvent.LastTimestamp = expectedEvent.LastTimestamp
// Check that name has the right prefix.
if n, en := recvEvent.Name, expectedEvent.Name; !strings.HasPrefix(n, en) {
t.Errorf("%v - Name '%v' does not contain prefix '%v'", messagePrefix, n, en)
}
recvEvent.Name = expectedEvent.Name
if e, a := expectedEvent, &recvEvent; !reflect.DeepEqual(e, a) {
t.Errorf("%v - diff: %s", messagePrefix, util.ObjectGoPrintDiff(e, a))
}
recvEvent.FirstTimestamp = actualFirstTimestamp
recvEvent.LastTimestamp = actualLastTimestamp
return actualEvent, nil
}
// TestDefaultEventFilterFunc ensures that no events are filtered
func TestDefaultEventFilterFunc(t *testing.T) {
event := makeEvent("end-of-world", "it was fun", makeObjectReference("Pod", "pod1", "other"))
if DefaultEventFilterFunc(&event) {
t.Fatalf("DefaultEventFilterFunc should always return false")
}
}
// TestEventAggregatorByReasonFunc ensures that two events are aggregated if they vary only by event.message
func TestEventAggregatorByReasonFunc(t *testing.T) {
event1 := makeEvent("end-of-world", "it was fun", makeObjectReference("Pod", "pod1", "other"))
event2 := makeEvent("end-of-world", "it was awful", makeObjectReference("Pod", "pod1", "other"))
event3 := makeEvent("nevermind", "it was a bug", makeObjectReference("Pod", "pod1", "other"))
aggKey1, localKey1 := EventAggregatorByReasonFunc(&event1)
aggKey2, localKey2 := EventAggregatorByReasonFunc(&event2)
aggKey3, _ := EventAggregatorByReasonFunc(&event3)
if aggKey1 != aggKey2 {
t.Errorf("Expected %v equal %v", aggKey1, aggKey2)
}
if localKey1 == localKey2 {
t.Errorf("Expected %v to not equal %v", aggKey1, aggKey3)
}
if aggKey1 == aggKey3 {
t.Errorf("Expected %v to not equal %v", aggKey1, aggKey3)
}
}
// TestEventAggregatorByReasonMessageFunc validates the proper output for an aggregate message
func TestEventAggregatorByReasonMessageFunc(t *testing.T) {
expected := "(events with common reason combined)"
event1 := makeEvent("end-of-world", "it was fun", makeObjectReference("Pod", "pod1", "other"))
if actual := EventAggregatorByReasonMessageFunc(&event1); expected != actual {
t.Errorf("Expected %v got %v", expected, actual)
}
}
// TestEventCorrelator validates proper counting, aggregation of events
func TestEventCorrelator(t *testing.T) {
firstEvent := makeEvent("first", "i am first", makeObjectReference("Pod", "my-pod", "my-ns"))
duplicateEvent := makeEvent("duplicate", "me again", makeObjectReference("Pod", "my-pod", "my-ns"))
uniqueEvent := makeEvent("unique", "snowflake", makeObjectReference("Pod", "my-pod", "my-ns"))
similarEvent := makeEvent("similar", "similar message", makeObjectReference("Pod", "my-pod", "my-ns"))
aggregateEvent := makeEvent(similarEvent.Reason, EventAggregatorByReasonMessageFunc(&similarEvent), similarEvent.InvolvedObject)
scenario := map[string]struct {
previousEvents []api.Event
newEvent api.Event
expectedEvent api.Event
intervalSeconds int
}{
"create-a-single-event": {
previousEvents: []api.Event{},
newEvent: firstEvent,
expectedEvent: setCount(firstEvent, 1),
intervalSeconds: 5,
},
"the-same-event-should-just-count": {
previousEvents: makeEvents(1, duplicateEvent),
newEvent: duplicateEvent,
expectedEvent: setCount(duplicateEvent, 2),
intervalSeconds: 5,
},
"the-same-event-should-just-count-even-if-more-than-aggregate": {
previousEvents: makeEvents(defaultAggregateMaxEvents, duplicateEvent),
newEvent: duplicateEvent,
expectedEvent: setCount(duplicateEvent, defaultAggregateMaxEvents+1),
intervalSeconds: 5,
},
"create-many-unique-events": {
previousEvents: makeUniqueEvents(30),
newEvent: uniqueEvent,
expectedEvent: setCount(uniqueEvent, 1),
intervalSeconds: 5,
},
"similar-events-should-aggregate-event": {
previousEvents: makeSimilarEvents(defaultAggregateMaxEvents-1, similarEvent, similarEvent.Message),
newEvent: similarEvent,
expectedEvent: setCount(aggregateEvent, 1),
intervalSeconds: 5,
},
"similar-events-many-times-should-count-the-aggregate": {
previousEvents: makeSimilarEvents(defaultAggregateMaxEvents, similarEvent, similarEvent.Message),
newEvent: similarEvent,
expectedEvent: setCount(aggregateEvent, 2),
intervalSeconds: 5,
},
"similar-events-whose-interval-is-greater-than-aggregate-interval-do-not-aggregate": {
previousEvents: makeSimilarEvents(defaultAggregateMaxEvents-1, similarEvent, similarEvent.Message),
newEvent: similarEvent,
expectedEvent: setCount(similarEvent, 1),
intervalSeconds: defaultAggregateIntervalInSeconds,
},
}
for testScenario, testInput := range scenario {
eventInterval := time.Duration(testInput.intervalSeconds) * time.Second
clock := util.IntervalClock{Time: time.Now(), Duration: eventInterval}
correlator := NewEventCorrelator(&clock)
for i := range testInput.previousEvents {
event := testInput.previousEvents[i]
now := unversioned.NewTime(clock.Now())
event.FirstTimestamp = now
event.LastTimestamp = now
result, err := correlator.EventCorrelate(&event)
if err != nil {
t.Errorf("scenario %v: unexpected error playing back prevEvents %v", testScenario, err)
}
correlator.UpdateState(result.Event)
}
// update the input to current clock value
now := unversioned.NewTime(clock.Now())
testInput.newEvent.FirstTimestamp = now
testInput.newEvent.LastTimestamp = now
result, err := correlator.EventCorrelate(&testInput.newEvent)
if err != nil {
t.Errorf("scenario %v: unexpected error correlating input event %v", testScenario, err)
}
_, err = validateEvent(testScenario, result.Event, &testInput.expectedEvent, t)
if err != nil {
t.Errorf("scenario %v: unexpected error validating result %v", testScenario, err)
}
}
}

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned
package restclient
import (
"net/http"

View file

@ -0,0 +1,309 @@
/*
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 restclient
import (
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"path"
gruntime "runtime"
"strings"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/version"
)
// Config holds the common attributes that can be passed to a Kubernetes client on
// initialization.
type Config struct {
// Host must be a host string, a host:port pair, or a URL to the base of the apiserver.
// If a URL is given then the (optional) Path of that URL represents a prefix that must
// be appended to all request URIs used to access the apiserver. This allows a frontend
// proxy to easily relocate all of the apiserver endpoints.
Host string
// APIPath is a sub-path that points to an API root.
APIPath string
// Prefix is the sub path of the server. If not specified, the client will set
// a default value. Use "/" to indicate the server root should be used
Prefix string
// ContentConfig contains settings that affect how objects are transformed when
// sent to the server.
ContentConfig
// Server requires Basic authentication
Username string
Password string
// Server requires Bearer authentication. This client will not attempt to use
// refresh tokens for an OAuth2 flow.
// TODO: demonstrate an OAuth2 compatible client.
BearerToken string
// TLSClientConfig contains settings to enable transport layer security
TLSClientConfig
// Server should be accessed without verifying the TLS
// certificate. For testing only.
Insecure bool
// UserAgent is an optional field that specifies the caller of this request.
UserAgent string
// Transport may be used for custom HTTP behavior. This attribute may not
// be specified with the TLS client certificate options. Use WrapTransport
// for most client level operations.
Transport http.RoundTripper
// WrapTransport will be invoked for custom HTTP behavior after the underlying
// transport is initialized (either the transport created from TLSClientConfig,
// Transport, or http.DefaultTransport). The config may layer other RoundTrippers
// on top of the returned RoundTripper.
WrapTransport func(rt http.RoundTripper) http.RoundTripper
// QPS indicates the maximum QPS to the master from this client. If zero, QPS is unlimited.
QPS float32
// Maximum burst for throttle
Burst int
}
// TLSClientConfig contains settings to enable transport layer security
type TLSClientConfig struct {
// Server requires TLS client certificate authentication
CertFile string
// Server requires TLS client certificate authentication
KeyFile string
// Trusted root certificates for server
CAFile string
// CertData holds PEM-encoded bytes (typically read from a client certificate file).
// CertData takes precedence over CertFile
CertData []byte
// KeyData holds PEM-encoded bytes (typically read from a client certificate key file).
// KeyData takes precedence over KeyFile
KeyData []byte
// CAData holds PEM-encoded bytes (typically read from a root certificates bundle).
// CAData takes precedence over CAFile
CAData []byte
}
type ContentConfig struct {
// ContentType specifies the wire format used to communicate with the server.
// This value will be set as the Accept header on requests made to the server, and
// as the default content type on any object sent to the server. If not set,
// "application/json" is used.
ContentType string
// GroupVersion is the API version to talk to. Must be provided when initializing
// a RESTClient directly. When initializing a Client, will be set with the default
// code version.
GroupVersion *unversioned.GroupVersion
// Codec specifies the encoding and decoding behavior for runtime.Objects passed
// to a RESTClient or Client. Required when initializing a RESTClient, optional
// when initializing a Client.
Codec runtime.Codec
}
// RESTClientFor returns a RESTClient that satisfies the requested attributes on a client Config
// object. Note that a RESTClient may require fields that are optional when initializing a Client.
// A RESTClient created by this method is generic - it expects to operate on an API that follows
// the Kubernetes conventions, but may not be the Kubernetes API.
func RESTClientFor(config *Config) (*RESTClient, error) {
if config.GroupVersion == nil {
return nil, fmt.Errorf("GroupVersion is required when initializing a RESTClient")
}
if config.Codec == nil {
return nil, fmt.Errorf("Codec is required when initializing a RESTClient")
}
baseURL, versionedAPIPath, err := defaultServerUrlFor(config)
if err != nil {
return nil, err
}
transport, err := TransportFor(config)
if err != nil {
return nil, err
}
var httpClient *http.Client
if transport != http.DefaultTransport {
httpClient = &http.Client{Transport: transport}
}
client := NewRESTClient(baseURL, versionedAPIPath, config.ContentConfig, config.QPS, config.Burst, httpClient)
return client, nil
}
// UnversionedRESTClientFor is the same as RESTClientFor, except that it allows
// the config.Version to be empty.
func UnversionedRESTClientFor(config *Config) (*RESTClient, error) {
if config.Codec == nil {
return nil, fmt.Errorf("Codec is required when initializing a RESTClient")
}
baseURL, versionedAPIPath, err := defaultServerUrlFor(config)
if err != nil {
return nil, err
}
transport, err := TransportFor(config)
if err != nil {
return nil, err
}
var httpClient *http.Client
if transport != http.DefaultTransport {
httpClient = &http.Client{Transport: transport}
}
versionConfig := config.ContentConfig
if versionConfig.GroupVersion == nil {
v := unversioned.SchemeGroupVersion
versionConfig.GroupVersion = &v
}
client := NewRESTClient(baseURL, versionedAPIPath, versionConfig, config.QPS, config.Burst, httpClient)
return client, nil
}
// SetKubernetesDefaults sets default values on the provided client config for accessing the
// Kubernetes API or returns an error if any of the defaults are impossible or invalid.
func SetKubernetesDefaults(config *Config) error {
if len(config.UserAgent) == 0 {
config.UserAgent = DefaultKubernetesUserAgent()
}
if config.QPS == 0.0 {
config.QPS = 5.0
}
if config.Burst == 0 {
config.Burst = 10
}
return nil
}
// DefaultKubernetesUserAgent returns the default user agent that clients can use.
func DefaultKubernetesUserAgent() string {
commit := version.Get().GitCommit
if len(commit) > 7 {
commit = commit[:7]
}
if len(commit) == 0 {
commit = "unknown"
}
version := version.Get().GitVersion
seg := strings.SplitN(version, "-", 2)
version = seg[0]
return fmt.Sprintf("%s/%s (%s/%s) kubernetes/%s", path.Base(os.Args[0]), version, gruntime.GOOS, gruntime.GOARCH, commit)
}
// InClusterConfig returns a config object which uses the service account
// kubernetes gives to pods. It's intended for clients that expect to be
// running inside a pod running on kuberenetes. It will return an error if
// called from a process not running in a kubernetes environment.
func InClusterConfig() (*Config, error) {
host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
if len(host) == 0 || len(port) == 0 {
return nil, fmt.Errorf("unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined")
}
token, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/" + api.ServiceAccountTokenKey)
if err != nil {
return nil, err
}
tlsClientConfig := TLSClientConfig{}
rootCAFile := "/var/run/secrets/kubernetes.io/serviceaccount/" + api.ServiceAccountRootCAKey
if _, err := util.CertPoolFromFile(rootCAFile); err != nil {
glog.Errorf("Expected to load root CA config from %s, but got err: %v", rootCAFile, err)
} else {
tlsClientConfig.CAFile = rootCAFile
}
return &Config{
// TODO: switch to using cluster DNS.
Host: "https://" + net.JoinHostPort(host, port),
BearerToken: string(token),
TLSClientConfig: tlsClientConfig,
}, nil
}
// IsConfigTransportTLS returns true if and only if the provided
// config will result in a protected connection to the server when it
// is passed to restclient.RESTClientFor(). Use to determine when to
// send credentials over the wire.
//
// Note: the Insecure flag is ignored when testing for this value, so MITM attacks are
// still possible.
func IsConfigTransportTLS(config Config) bool {
baseURL, _, err := defaultServerUrlFor(&config)
if err != nil {
return false
}
return baseURL.Scheme == "https"
}
// LoadTLSFiles copies the data from the CertFile, KeyFile, and CAFile fields into the CertData,
// KeyData, and CAFile fields, or returns an error. If no error is returned, all three fields are
// either populated or were empty to start.
func LoadTLSFiles(c *Config) error {
var err error
c.CAData, err = dataFromSliceOrFile(c.CAData, c.CAFile)
if err != nil {
return err
}
c.CertData, err = dataFromSliceOrFile(c.CertData, c.CertFile)
if err != nil {
return err
}
c.KeyData, err = dataFromSliceOrFile(c.KeyData, c.KeyFile)
if err != nil {
return err
}
return nil
}
// dataFromSliceOrFile returns data from the slice (if non-empty), or from the file,
// or an error if an error occurred reading the file
func dataFromSliceOrFile(data []byte, file string) ([]byte, error) {
if len(data) > 0 {
return data, nil
}
if len(file) > 0 {
fileData, err := ioutil.ReadFile(file)
if err != nil {
return []byte{}, err
}
return fileData, nil
}
return nil, nil
}
func AddUserAgent(config *Config, userAgent string) *Config {
fullUserAgent := DefaultKubernetesUserAgent() + "/" + userAgent
config.UserAgent = fullUserAgent
return config
}

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned
package restclient
import (
"bytes"
@ -292,22 +292,22 @@ func (r *Request) RequestURI(uri string) *Request {
const (
// A constant that clients can use to refer in a field selector to the object name field.
// Will be automatically emitted as the correct name for the API version.
NodeUnschedulable = "spec.unschedulable"
ObjectNameField = "metadata.name"
PodHost = "spec.nodeName"
PodStatus = "status.phase"
SecretType = "type"
nodeUnschedulable = "spec.unschedulable"
objectNameField = "metadata.name"
podHost = "spec.nodeName"
podStatus = "status.phase"
secretType = "type"
EventReason = "reason"
EventSource = "source"
EventType = "type"
EventInvolvedKind = "involvedObject.kind"
EventInvolvedNamespace = "involvedObject.namespace"
EventInvolvedName = "involvedObject.name"
EventInvolvedUID = "involvedObject.uid"
EventInvolvedAPIVersion = "involvedObject.apiVersion"
EventInvolvedResourceVersion = "involvedObject.resourceVersion"
EventInvolvedFieldPath = "involvedObject.fieldPath"
eventReason = "reason"
eventSource = "source"
eventType = "type"
eventInvolvedKind = "involvedObject.kind"
eventInvolvedNamespace = "involvedObject.namespace"
eventInvolvedName = "involvedObject.name"
eventInvolvedUID = "involvedObject.uid"
eventInvolvedAPIVersion = "involvedObject.apiVersion"
eventInvolvedResourceVersion = "involvedObject.resourceVersion"
eventInvolvedFieldPath = "involvedObject.fieldPath"
)
type clientFieldNameToAPIVersionFieldName map[string]string
@ -350,34 +350,34 @@ func (v versionToResourceToFieldMapping) filterField(groupVersion *unversioned.G
var fieldMappings = versionToResourceToFieldMapping{
v1.SchemeGroupVersion: resourceTypeToFieldMapping{
"nodes": clientFieldNameToAPIVersionFieldName{
ObjectNameField: ObjectNameField,
NodeUnschedulable: NodeUnschedulable,
objectNameField: objectNameField,
nodeUnschedulable: nodeUnschedulable,
},
"pods": clientFieldNameToAPIVersionFieldName{
PodHost: PodHost,
PodStatus: PodStatus,
podHost: podHost,
podStatus: podStatus,
},
"secrets": clientFieldNameToAPIVersionFieldName{
SecretType: SecretType,
secretType: secretType,
},
"serviceAccounts": clientFieldNameToAPIVersionFieldName{
ObjectNameField: ObjectNameField,
objectNameField: objectNameField,
},
"endpoints": clientFieldNameToAPIVersionFieldName{
ObjectNameField: ObjectNameField,
objectNameField: objectNameField,
},
"events": clientFieldNameToAPIVersionFieldName{
ObjectNameField: ObjectNameField,
EventReason: EventReason,
EventSource: EventSource,
EventType: EventType,
EventInvolvedKind: EventInvolvedKind,
EventInvolvedNamespace: EventInvolvedNamespace,
EventInvolvedName: EventInvolvedName,
EventInvolvedUID: EventInvolvedUID,
EventInvolvedAPIVersion: EventInvolvedAPIVersion,
EventInvolvedResourceVersion: EventInvolvedResourceVersion,
EventInvolvedFieldPath: EventInvolvedFieldPath,
objectNameField: objectNameField,
eventReason: eventReason,
eventSource: eventSource,
eventType: eventType,
eventInvolvedKind: eventInvolvedKind,
eventInvolvedNamespace: eventInvolvedNamespace,
eventInvolvedName: eventInvolvedName,
eventInvolvedUID: eventInvolvedUID,
eventInvolvedAPIVersion: eventInvolvedAPIVersion,
eventInvolvedResourceVersion: eventInvolvedResourceVersion,
eventInvolvedFieldPath: eventInvolvedFieldPath,
},
},
}
@ -624,7 +624,7 @@ func (r *Request) tryThrottle() {
r.throttle.Accept()
}
if latency := time.Since(now); latency > longThrottleLatency {
glog.Warningf("Throttling request took %v, request: %s", latency, r.URL().String())
glog.Warningf("Throttling request took %v, request: %s:%s", latency, r.verb, r.URL().String())
}
}
@ -645,7 +645,7 @@ func (r *Request) Watch() (watch.Interface, error) {
if client == nil {
client = http.DefaultClient
}
time.Sleep(r.backoffMgr.CalculateBackoff(r.URL()))
r.backoffMgr.Sleep(r.backoffMgr.CalculateBackoff(r.URL()))
resp, err := client.Do(req)
updateURLMetrics(r, resp, err)
if r.baseURL != nil {
@ -710,7 +710,7 @@ func (r *Request) Stream() (io.ReadCloser, error) {
if client == nil {
client = http.DefaultClient
}
time.Sleep(r.backoffMgr.CalculateBackoff(r.URL()))
r.backoffMgr.Sleep(r.backoffMgr.CalculateBackoff(r.URL()))
resp, err := client.Do(req)
updateURLMetrics(r, resp, err)
if r.baseURL != nil {
@ -792,7 +792,7 @@ func (r *Request) request(fn func(*http.Request, *http.Response)) error {
}
req.Header = r.headers
time.Sleep(r.backoffMgr.CalculateBackoff(r.URL()))
r.backoffMgr.Sleep(r.backoffMgr.CalculateBackoff(r.URL()))
resp, err := client.Do(req)
updateURLMetrics(r, resp, err)
if err != nil {
@ -812,7 +812,7 @@ func (r *Request) request(fn func(*http.Request, *http.Response)) error {
retries++
if seconds, wait := checkWait(resp); wait && retries < maxRetries {
glog.V(4).Infof("Got a Retry-After %s response for attempt %d to %v", seconds, retries, url)
time.Sleep(time.Duration(seconds) * time.Second)
r.backoffMgr.Sleep(time.Duration(seconds) * time.Second)
return false
}
fn(req, resp)

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned
package restclient
import (
"crypto/tls"

View file

@ -0,0 +1,93 @@
/*
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 restclient
import (
"fmt"
"net/url"
"path"
"k8s.io/kubernetes/pkg/api/unversioned"
)
// DefaultServerURL converts a host, host:port, or URL string to the default base server API path
// to use with a Client at a given API version following the standard conventions for a
// Kubernetes API.
func DefaultServerURL(host, apiPath string, groupVersion unversioned.GroupVersion, defaultTLS bool) (*url.URL, string, error) {
if host == "" {
return nil, "", fmt.Errorf("host must be a URL or a host:port pair")
}
base := host
hostURL, err := url.Parse(base)
if err != nil {
return nil, "", err
}
if hostURL.Scheme == "" {
scheme := "http://"
if defaultTLS {
scheme = "https://"
}
hostURL, err = url.Parse(scheme + base)
if err != nil {
return nil, "", err
}
if hostURL.Path != "" && hostURL.Path != "/" {
return nil, "", fmt.Errorf("host must be a URL or a host:port pair: %q", base)
}
}
// hostURL.Path is optional; a non-empty Path is treated as a prefix that is to be applied to
// all URIs used to access the host. this is useful when there's a proxy in front of the
// apiserver that has relocated the apiserver endpoints, forwarding all requests from, for
// example, /a/b/c to the apiserver. in this case the Path should be /a/b/c.
//
// if running without a frontend proxy (that changes the location of the apiserver), then
// hostURL.Path should be blank.
//
// versionedAPIPath, a path relative to baseURL.Path, points to a versioned API base
versionedAPIPath := path.Join("/", apiPath)
// Add the version to the end of the path
if len(groupVersion.Group) > 0 {
versionedAPIPath = path.Join(versionedAPIPath, groupVersion.Group, groupVersion.Version)
} else {
versionedAPIPath = path.Join(versionedAPIPath, groupVersion.Version)
}
return hostURL, versionedAPIPath, nil
}
// defaultServerUrlFor is shared between IsConfigTransportTLS and RESTClientFor. It
// requires Host and Version to be set prior to being called.
func defaultServerUrlFor(config *Config) (*url.URL, string, error) {
// TODO: move the default to secure when the apiserver supports TLS by default
// config.Insecure is taken to mean "I want HTTPS but don't bother checking the certs against a CA."
hasCA := len(config.CAFile) != 0 || len(config.CAData) != 0
hasCert := len(config.CertFile) != 0 || len(config.CertData) != 0
defaultTLS := hasCA || hasCert || config.Insecure
host := config.Host
if host == "" {
host = "localhost"
}
if config.GroupVersion != nil {
return DefaultServerURL(host, config.APIPath, *config.GroupVersion, defaultTLS)
}
return DefaultServerURL(host, config.APIPath, unversioned.GroupVersion{}, defaultTLS)
}

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned
package restclient
import (
"net/url"
@ -35,6 +35,7 @@ var maxResponseCode = 499
type BackoffManager interface {
UpdateBackoff(actualUrl *url.URL, err error, responseCode int)
CalculateBackoff(actualUrl *url.URL) time.Duration
Sleep(d time.Duration)
}
// URLBackoff struct implements the semantics on top of Backoff which
@ -54,6 +55,9 @@ func (n *NoBackoff) UpdateBackoff(actualUrl *url.URL, err error, responseCode in
func (n *NoBackoff) CalculateBackoff(actualUrl *url.URL) time.Duration {
return 0 * time.Second
}
func (n *NoBackoff) Sleep(d time.Duration) {
return
}
// Disable makes the backoff trivial, i.e., sets it to zero. This might be used
// by tests which want to run 1000s of mock requests without slowing down.
@ -80,7 +84,7 @@ func (b *URLBackoff) baseUrlKey(rawurl *url.URL) string {
func (b *URLBackoff) UpdateBackoff(actualUrl *url.URL, err error, responseCode int) {
// range for retry counts that we store is [0,13]
if responseCode > maxResponseCode || serverIsOverloadedSet.Has(responseCode) {
b.Backoff.Next(b.baseUrlKey(actualUrl), time.Now())
b.Backoff.Next(b.baseUrlKey(actualUrl), b.Backoff.Clock.Now())
return
} else if responseCode >= 300 || err != nil {
glog.V(4).Infof("Client is returning errors: code %v, error %v", responseCode, err)
@ -95,3 +99,7 @@ func (b *URLBackoff) UpdateBackoff(actualUrl *url.URL, err error, responseCode i
func (b *URLBackoff) CalculateBackoff(actualUrl *url.URL) time.Duration {
return b.Backoff.Get(b.baseUrlKey(actualUrl))
}
func (b *URLBackoff) Sleep(d time.Duration) {
b.Backoff.Clock.Sleep(d)
}

View file

@ -0,0 +1,88 @@
/*
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 restclient
import (
"encoding/json"
"fmt"
"net/http"
"path"
"k8s.io/kubernetes/pkg/api/unversioned"
)
const (
legacyAPIPath = "/api"
defaultAPIPath = "/apis"
)
// TODO: Is this obsoleted by the discovery client?
// ServerAPIVersions returns the GroupVersions supported by the API server.
// It creates a RESTClient based on the passed in config, but it doesn't rely
// on the Version and Codec of the config, because it uses AbsPath and
// takes the raw response.
func ServerAPIVersions(c *Config) (groupVersions []string, err error) {
transport, err := TransportFor(c)
if err != nil {
return nil, err
}
client := http.Client{Transport: transport}
configCopy := *c
configCopy.GroupVersion = nil
configCopy.APIPath = ""
baseURL, _, err := defaultServerUrlFor(&configCopy)
if err != nil {
return nil, err
}
// Get the groupVersions exposed at /api
originalPath := baseURL.Path
baseURL.Path = path.Join(originalPath, legacyAPIPath)
resp, err := client.Get(baseURL.String())
if err != nil {
return nil, err
}
var v unversioned.APIVersions
defer resp.Body.Close()
err = json.NewDecoder(resp.Body).Decode(&v)
if err != nil {
return nil, fmt.Errorf("unexpected error: %v", err)
}
groupVersions = append(groupVersions, v.Versions...)
// Get the groupVersions exposed at /apis
baseURL.Path = path.Join(originalPath, defaultAPIPath)
resp2, err := client.Get(baseURL.String())
if err != nil {
return nil, err
}
var apiGroupList unversioned.APIGroupList
defer resp2.Body.Close()
err = json.NewDecoder(resp2.Body).Decode(&apiGroupList)
if err != nil {
return nil, fmt.Errorf("unexpected error: %v", err)
}
for _, g := range apiGroupList.Groups {
for _, gv := range g.Versions {
groupVersions = append(groupVersions, gv.GroupVersion)
}
}
return groupVersions, nil
}

View file

@ -1,114 +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 transport
import (
"net/http"
"testing"
)
func TestTLSConfigKey(t *testing.T) {
// Make sure config fields that don't affect the tls config don't affect the cache key
identicalConfigurations := map[string]*Config{
"empty": {},
"basic": {Username: "bob", Password: "password"},
"bearer": {BearerToken: "token"},
"user agent": {UserAgent: "useragent"},
"transport": {Transport: http.DefaultTransport},
"wrap transport": {WrapTransport: func(http.RoundTripper) http.RoundTripper { return nil }},
}
for nameA, valueA := range identicalConfigurations {
for nameB, valueB := range identicalConfigurations {
keyA, err := tlsConfigKey(valueA)
if err != nil {
t.Errorf("Unexpected error for %q: %v", nameA, err)
continue
}
keyB, err := tlsConfigKey(valueB)
if err != nil {
t.Errorf("Unexpected error for %q: %v", nameB, err)
continue
}
if keyA != keyB {
t.Errorf("Expected identical cache keys for %q and %q, got:\n\t%s\n\t%s", nameA, nameB, keyA, keyB)
continue
}
}
}
// Make sure config fields that affect the tls config affect the cache key
uniqueConfigurations := map[string]*Config{
"no tls": {},
"insecure": {TLS: TLSConfig{Insecure: true}},
"cadata 1": {TLS: TLSConfig{CAData: []byte{1}}},
"cadata 2": {TLS: TLSConfig{CAData: []byte{2}}},
"cert 1, key 1": {
TLS: TLSConfig{
CertData: []byte{1},
KeyData: []byte{1},
},
},
"cert 1, key 2": {
TLS: TLSConfig{
CertData: []byte{1},
KeyData: []byte{2},
},
},
"cert 2, key 1": {
TLS: TLSConfig{
CertData: []byte{2},
KeyData: []byte{1},
},
},
"cert 2, key 2": {
TLS: TLSConfig{
CertData: []byte{2},
KeyData: []byte{2},
},
},
"cadata 1, cert 1, key 1": {
TLS: TLSConfig{
CAData: []byte{1},
CertData: []byte{1},
KeyData: []byte{1},
},
},
}
for nameA, valueA := range uniqueConfigurations {
for nameB, valueB := range uniqueConfigurations {
// Don't compare to ourselves
if nameA == nameB {
continue
}
keyA, err := tlsConfigKey(valueA)
if err != nil {
t.Errorf("Unexpected error for %q: %v", nameA, err)
continue
}
keyB, err := tlsConfigKey(valueB)
if err != nil {
t.Errorf("Unexpected error for %q: %v", nameB, err)
continue
}
if keyA == keyB {
t.Errorf("Expected unique cache keys for %q and %q, got:\n\t%s\n\t%s", nameA, nameB, keyA, keyB)
continue
}
}
}
}

View file

@ -1,101 +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 transport
import (
"net/http"
"testing"
)
type testRoundTripper struct {
Request *http.Request
Response *http.Response
Err error
}
func (rt *testRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
rt.Request = req
return rt.Response, rt.Err
}
func TestBearerAuthRoundTripper(t *testing.T) {
rt := &testRoundTripper{}
req := &http.Request{}
NewBearerAuthRoundTripper("test", rt).RoundTrip(req)
if rt.Request == nil {
t.Fatalf("unexpected nil request: %v", rt)
}
if rt.Request == req {
t.Fatalf("round tripper should have copied request object: %#v", rt.Request)
}
if rt.Request.Header.Get("Authorization") != "Bearer test" {
t.Errorf("unexpected authorization header: %#v", rt.Request)
}
}
func TestBasicAuthRoundTripper(t *testing.T) {
for n, tc := range map[string]struct {
user string
pass string
}{
"basic": {user: "user", pass: "pass"},
"no pass": {user: "user"},
} {
rt := &testRoundTripper{}
req := &http.Request{}
NewBasicAuthRoundTripper(tc.user, tc.pass, rt).RoundTrip(req)
if rt.Request == nil {
t.Fatalf("%s: unexpected nil request: %v", n, rt)
}
if rt.Request == req {
t.Fatalf("%s: round tripper should have copied request object: %#v", n, rt.Request)
}
if user, pass, found := rt.Request.BasicAuth(); !found || user != tc.user || pass != tc.pass {
t.Errorf("%s: unexpected authorization header: %#v", n, rt.Request)
}
}
}
func TestUserAgentRoundTripper(t *testing.T) {
rt := &testRoundTripper{}
req := &http.Request{
Header: make(http.Header),
}
req.Header.Set("User-Agent", "other")
NewUserAgentRoundTripper("test", rt).RoundTrip(req)
if rt.Request == nil {
t.Fatalf("unexpected nil request: %v", rt)
}
if rt.Request != req {
t.Fatalf("round tripper should not have copied request object: %#v", rt.Request)
}
if rt.Request.Header.Get("User-Agent") != "other" {
t.Errorf("unexpected user agent header: %#v", rt.Request)
}
req = &http.Request{}
NewUserAgentRoundTripper("test", rt).RoundTrip(req)
if rt.Request == nil {
t.Fatalf("unexpected nil request: %v", rt)
}
if rt.Request == req {
t.Fatalf("round tripper should have copied request object: %#v", rt.Request)
}
if rt.Request.Header.Get("User-Agent") != "test" {
t.Errorf("unexpected user agent header: %#v", rt.Request)
}
}

View file

@ -1,204 +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 transport
import (
"net/http"
"testing"
)
const (
rootCACert = `-----BEGIN CERTIFICATE-----
MIIC4DCCAcqgAwIBAgIBATALBgkqhkiG9w0BAQswIzEhMB8GA1UEAwwYMTAuMTMu
MTI5LjEwNkAxNDIxMzU5MDU4MB4XDTE1MDExNTIxNTczN1oXDTE2MDExNTIxNTcz
OFowIzEhMB8GA1UEAwwYMTAuMTMuMTI5LjEwNkAxNDIxMzU5MDU4MIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAunDRXGwsiYWGFDlWH6kjGun+PshDGeZX
xtx9lUnL8pIRWH3wX6f13PO9sktaOWW0T0mlo6k2bMlSLlSZgG9H6og0W6gLS3vq
s4VavZ6DbXIwemZG2vbRwsvR+t4G6Nbwelm6F8RFnA1Fwt428pavmNQ/wgYzo+T1
1eS+HiN4ACnSoDSx3QRWcgBkB1g6VReofVjx63i0J+w8Q/41L9GUuLqquFxu6ZnH
60vTB55lHgFiDLjA1FkEz2dGvGh/wtnFlRvjaPC54JH2K1mPYAUXTreoeJtLJKX0
ycoiyB24+zGCniUmgIsmQWRPaOPircexCp1BOeze82BT1LCZNTVaxQIDAQABoyMw
ITAOBgNVHQ8BAf8EBAMCAKQwDwYDVR0TAQH/BAUwAwEB/zALBgkqhkiG9w0BAQsD
ggEBADMxsUuAFlsYDpF4fRCzXXwrhbtj4oQwcHpbu+rnOPHCZupiafzZpDu+rw4x
YGPnCb594bRTQn4pAu3Ac18NbLD5pV3uioAkv8oPkgr8aUhXqiv7KdDiaWm6sbAL
EHiXVBBAFvQws10HMqMoKtO8f1XDNAUkWduakR/U6yMgvOPwS7xl0eUTqyRB6zGb
K55q2dejiFWaFqB/y78txzvz6UlOZKE44g2JAVoJVM6kGaxh33q8/FmrL4kuN3ut
W+MmJCVDvd4eEqPwbp7146ZWTqpIJ8lvA6wuChtqV8lhAPka2hD/LMqY8iXNmfXD
uml0obOEy+ON91k+SWTJ3ggmF/U=
-----END CERTIFICATE-----`
certData = `-----BEGIN CERTIFICATE-----
MIIC6jCCAdSgAwIBAgIBCzALBgkqhkiG9w0BAQswIzEhMB8GA1UEAwwYMTAuMTMu
MTI5LjEwNkAxNDIxMzU5MDU4MB4XDTE1MDExNTIyMDEzMVoXDTE2MDExNTIyMDEz
MlowGzEZMBcGA1UEAxMQb3BlbnNoaWZ0LWNsaWVudDCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAKtdhz0+uCLXw5cSYns9rU/XifFSpb/x24WDdrm72S/v
b9BPYsAStiP148buylr1SOuNi8sTAZmlVDDIpIVwMLff+o2rKYDicn9fjbrTxTOj
lI4pHJBH+JU3AJ0tbajupioh70jwFS0oYpwtneg2zcnE2Z4l6mhrj2okrc5Q1/X2
I2HChtIU4JYTisObtin10QKJX01CLfYXJLa8upWzKZ4/GOcHG+eAV3jXWoXidtjb
1Usw70amoTZ6mIVCkiu1QwCoa8+ycojGfZhvqMsAp1536ZcCul+Na+AbCv4zKS7F
kQQaImVrXdUiFansIoofGlw/JNuoKK6ssVpS5Ic3pgcCAwEAAaM1MDMwDgYDVR0P
AQH/BAQDAgCgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwCwYJ
KoZIhvcNAQELA4IBAQCKLREH7bXtXtZ+8vI6cjD7W3QikiArGqbl36bAhhWsJLp/
p/ndKz39iFNaiZ3GlwIURWOOKx3y3GA0x9m8FR+Llthf0EQ8sUjnwaknWs0Y6DQ3
jjPFZOpV3KPCFrdMJ3++E3MgwFC/Ih/N2ebFX9EcV9Vcc6oVWMdwT0fsrhu683rq
6GSR/3iVX1G/pmOiuaR0fNUaCyCfYrnI4zHBDgSfnlm3vIvN2lrsR/DQBakNL8DJ
HBgKxMGeUPoneBv+c8DMXIL0EhaFXRlBv9QW45/GiAIOuyFJ0i6hCtGZpJjq4OpQ
BRjCI+izPzFTjsxD4aORE+WOkyWFCGPWKfNejfw0
-----END CERTIFICATE-----`
keyData = `-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAq12HPT64ItfDlxJiez2tT9eJ8VKlv/HbhYN2ubvZL+9v0E9i
wBK2I/Xjxu7KWvVI642LyxMBmaVUMMikhXAwt9/6jaspgOJyf1+NutPFM6OUjikc
kEf4lTcAnS1tqO6mKiHvSPAVLShinC2d6DbNycTZniXqaGuPaiStzlDX9fYjYcKG
0hTglhOKw5u2KfXRAolfTUIt9hcktry6lbMpnj8Y5wcb54BXeNdaheJ22NvVSzDv
RqahNnqYhUKSK7VDAKhrz7JyiMZ9mG+oywCnXnfplwK6X41r4BsK/jMpLsWRBBoi
ZWtd1SIVqewiih8aXD8k26gorqyxWlLkhzemBwIDAQABAoIBAD2XYRs3JrGHQUpU
FkdbVKZkvrSY0vAZOqBTLuH0zUv4UATb8487anGkWBjRDLQCgxH+jucPTrztekQK
aW94clo0S3aNtV4YhbSYIHWs1a0It0UdK6ID7CmdWkAj6s0T8W8lQT7C46mWYVLm
5mFnCTHi6aB42jZrqmEpC7sivWwuU0xqj3Ml8kkxQCGmyc9JjmCB4OrFFC8NNt6M
ObvQkUI6Z3nO4phTbpxkE1/9dT0MmPIF7GhHVzJMS+EyyRYUDllZ0wvVSOM3qZT0
JMUaBerkNwm9foKJ1+dv2nMKZZbJajv7suUDCfU44mVeaEO+4kmTKSGCGjjTBGkr
7L1ySDECgYEA5ElIMhpdBzIivCuBIH8LlUeuzd93pqssO1G2Xg0jHtfM4tz7fyeI
cr90dc8gpli24dkSxzLeg3Tn3wIj/Bu64m2TpZPZEIlukYvgdgArmRIPQVxerYey
OkrfTNkxU1HXsYjLCdGcGXs5lmb+K/kuTcFxaMOs7jZi7La+jEONwf8CgYEAwCs/
rUOOA0klDsWWisbivOiNPII79c9McZCNBqncCBfMUoiGe8uWDEO4TFHN60vFuVk9
8PkwpCfvaBUX+ajvbafIfHxsnfk1M04WLGCeqQ/ym5Q4sQoQOcC1b1y9qc/xEWfg
nIUuia0ukYRpl7qQa3tNg+BNFyjypW8zukUAC/kCgYB1/Kojuxx5q5/oQVPrx73k
2bevD+B3c+DYh9MJqSCNwFtUpYIWpggPxoQan4LwdsmO0PKzocb/ilyNFj4i/vII
NToqSc/WjDFpaDIKyuu9oWfhECye45NqLWhb/6VOuu4QA/Nsj7luMhIBehnEAHW+
GkzTKM8oD1PxpEG3nPKXYQKBgQC6AuMPRt3XBl1NkCrpSBy/uObFlFaP2Enpf39S
3OZ0Gv0XQrnSaL1kP8TMcz68rMrGX8DaWYsgytstR4W+jyy7WvZwsUu+GjTJ5aMG
77uEcEBpIi9CBzivfn7hPccE8ZgqPf+n4i6q66yxBJflW5xhvafJqDtW2LcPNbW/
bvzdmQKBgExALRUXpq+5dbmkdXBHtvXdRDZ6rVmrnjy4nI5bPw+1GqQqk6uAR6B/
F6NmLCQOO4PDG/cuatNHIr2FrwTmGdEL6ObLUGWn9Oer9gJhHVqqsY5I4sEPo4XX
stR0Yiw0buV6DL/moUO0HIM9Bjh96HJp+LxiIS6UCdIhMPp5HoQa
-----END RSA PRIVATE KEY-----`
)
func TestNew(t *testing.T) {
testCases := map[string]struct {
Config *Config
Err bool
TLS bool
Default bool
}{
"default transport": {
Default: true,
Config: &Config{},
},
"ca transport": {
TLS: true,
Config: &Config{
TLS: TLSConfig{
CAData: []byte(rootCACert),
},
},
},
"bad ca file transport": {
Err: true,
Config: &Config{
TLS: TLSConfig{
CAFile: "invalid file",
},
},
},
"ca data overriding bad ca file transport": {
TLS: true,
Config: &Config{
TLS: TLSConfig{
CAData: []byte(rootCACert),
CAFile: "invalid file",
},
},
},
"cert transport": {
TLS: true,
Config: &Config{
TLS: TLSConfig{
CAData: []byte(rootCACert),
CertData: []byte(certData),
KeyData: []byte(keyData),
},
},
},
"bad cert data transport": {
Err: true,
Config: &Config{
TLS: TLSConfig{
CAData: []byte(rootCACert),
CertData: []byte(certData),
KeyData: []byte("bad key data"),
},
},
},
"bad file cert transport": {
Err: true,
Config: &Config{
TLS: TLSConfig{
CAData: []byte(rootCACert),
CertData: []byte(certData),
KeyFile: "invalid file",
},
},
},
"key data overriding bad file cert transport": {
TLS: true,
Config: &Config{
TLS: TLSConfig{
CAData: []byte(rootCACert),
CertData: []byte(certData),
KeyData: []byte(keyData),
KeyFile: "invalid file",
},
},
},
}
for k, testCase := range testCases {
transport, err := New(testCase.Config)
switch {
case testCase.Err && err == nil:
t.Errorf("%s: unexpected non-error", k)
continue
case !testCase.Err && err != nil:
t.Errorf("%s: unexpected error: %v", k, err)
continue
}
switch {
case testCase.Default && transport != http.DefaultTransport:
t.Errorf("%s: expected the default transport, got %#v", k, transport)
continue
case !testCase.Default && transport == http.DefaultTransport:
t.Errorf("%s: expected non-default transport, got %#v", k, transport)
continue
}
// We only know how to check TLSConfig on http.Transports
if transport, ok := transport.(*http.Transport); ok {
switch {
case testCase.TLS && transport.TLSClientConfig == nil:
t.Errorf("%s: expected TLSClientConfig, got %#v", k, transport)
continue
case !testCase.TLS && transport.TLSClientConfig != nil:
t.Errorf("%s: expected no TLSClientConfig, got %#v", k, transport)
continue
}
}
}
}

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned
package discovery
import (
"encoding/json"
@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/version"
)
@ -70,7 +71,7 @@ type SwaggerSchemaInterface interface {
// DiscoveryClient implements the functions that discover server-supported API groups,
// versions and resources.
type DiscoveryClient struct {
*RESTClient
*restclient.RESTClient
}
// Convert unversioned.APIVersions to unversioned.APIGroup. APIVersions is used by legacy v1, so
@ -147,7 +148,7 @@ func (d *DiscoveryClient) ServerResources() (map[string]*unversioned.APIResource
if err != nil {
return nil, err
}
groupVersions := ExtractGroupVersions(apiGroups)
groupVersions := unversioned.ExtractGroupVersions(apiGroups)
result := map[string]*unversioned.APIResourceList{}
for _, groupVersion := range groupVersions {
resources, err := d.ServerResourcesForGroupVersion(groupVersion)
@ -183,7 +184,7 @@ func (d *DiscoveryClient) SwaggerSchema(version unversioned.GroupVersion) (*swag
if err != nil {
return nil, err
}
groupVersions := ExtractGroupVersions(groupList)
groupVersions := unversioned.ExtractGroupVersions(groupList)
// This check also takes care the case that kubectl is newer than the running endpoint
if stringDoesntExistIn(version.String(), groupVersions) {
return nil, fmt.Errorf("API version: %v is not supported by the server. Use one of: %v", version, groupVersions)
@ -207,27 +208,30 @@ func (d *DiscoveryClient) SwaggerSchema(version unversioned.GroupVersion) (*swag
return &schema, nil
}
func setDiscoveryDefaults(config *Config) error {
func setDiscoveryDefaults(config *restclient.Config) error {
config.APIPath = ""
config.GroupVersion = nil
config.Codec = runtime.NoopEncoder{api.Codecs.UniversalDecoder()}
if len(config.UserAgent) == 0 {
config.UserAgent = restclient.DefaultKubernetesUserAgent()
}
return nil
}
// NewDiscoveryClientForConfig creates a new DiscoveryClient for the given config. This client
// can be used to discover supported resources in the API server.
func NewDiscoveryClientForConfig(c *Config) (*DiscoveryClient, error) {
func NewDiscoveryClientForConfig(c *restclient.Config) (*DiscoveryClient, error) {
config := *c
if err := setDiscoveryDefaults(&config); err != nil {
return nil, err
}
client, err := UnversionedRESTClientFor(&config)
client, err := restclient.UnversionedRESTClientFor(&config)
return &DiscoveryClient{client}, err
}
// NewDiscoveryClientForConfig creates a new DiscoveryClient for the given config. If
// there is an error, it panics.
func NewDiscoveryClientForConfigOrDie(c *Config) *DiscoveryClient {
func NewDiscoveryClientForConfigOrDie(c *restclient.Config) *DiscoveryClient {
client, err := NewDiscoveryClientForConfig(c)
if err != nil {
panic(err)
@ -237,6 +241,15 @@ func NewDiscoveryClientForConfigOrDie(c *Config) *DiscoveryClient {
}
// New creates a new DiscoveryClient for the given RESTClient.
func NewDiscoveryClient(c *RESTClient) *DiscoveryClient {
func NewDiscoveryClient(c *restclient.RESTClient) *DiscoveryClient {
return &DiscoveryClient{c}
}
func stringDoesntExistIn(str string, slice []string) bool {
for _, s := range slice {
if s == str {
return false
}
}
return true
}

View file

@ -19,7 +19,7 @@ package unversioned
import (
api "k8s.io/kubernetes/pkg/api"
registered "k8s.io/kubernetes/pkg/apimachinery/registered"
unversioned "k8s.io/kubernetes/pkg/client/unversioned"
restclient "k8s.io/kubernetes/pkg/client/restclient"
)
type CoreInterface interface {
@ -43,7 +43,7 @@ type CoreInterface interface {
// CoreClient is used to interact with features provided by the Core group.
type CoreClient struct {
*unversioned.RESTClient
*restclient.RESTClient
}
func (c *CoreClient) ComponentStatuses() ComponentStatusInterface {
@ -111,12 +111,12 @@ func (c *CoreClient) ServiceAccounts(namespace string) ServiceAccountInterface {
}
// NewForConfig creates a new CoreClient for the given config.
func NewForConfig(c *unversioned.Config) (*CoreClient, error) {
func NewForConfig(c *restclient.Config) (*CoreClient, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
}
client, err := unversioned.RESTClientFor(&config)
client, err := restclient.RESTClientFor(&config)
if err != nil {
return nil, err
}
@ -125,7 +125,7 @@ func NewForConfig(c *unversioned.Config) (*CoreClient, error) {
// NewForConfigOrDie creates a new CoreClient for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *unversioned.Config) *CoreClient {
func NewForConfigOrDie(c *restclient.Config) *CoreClient {
client, err := NewForConfig(c)
if err != nil {
panic(err)
@ -134,11 +134,11 @@ func NewForConfigOrDie(c *unversioned.Config) *CoreClient {
}
// New creates a new CoreClient for the given RESTClient.
func New(c *unversioned.RESTClient) *CoreClient {
func New(c *restclient.RESTClient) *CoreClient {
return &CoreClient{c}
}
func setConfigDefaults(config *unversioned.Config) error {
func setConfigDefaults(config *restclient.Config) error {
// if core group is not registered, return an error
g, err := registered.Group("")
if err != nil {
@ -146,7 +146,7 @@ func setConfigDefaults(config *unversioned.Config) error {
}
config.APIPath = "/api"
if config.UserAgent == "" {
config.UserAgent = unversioned.DefaultKubernetesUserAgent()
config.UserAgent = restclient.DefaultKubernetesUserAgent()
}
// TODO: Unconditionally set the config.Version, until we fix the config.
//if config.Version == "" {

View file

@ -1,18 +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 fake has the automatically generated clients.
package fake

View file

@ -1,95 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeComponentStatuses implements ComponentStatusInterface
type FakeComponentStatuses struct {
Fake *FakeCore
}
func (c *FakeComponentStatuses) Create(componentStatus *api.ComponentStatus) (result *api.ComponentStatus, err error) {
obj, err := c.Fake.
Invokes(core.NewRootCreateAction("componentstatuses", componentStatus), &api.ComponentStatus{})
if obj == nil {
return nil, err
}
return obj.(*api.ComponentStatus), err
}
func (c *FakeComponentStatuses) Update(componentStatus *api.ComponentStatus) (result *api.ComponentStatus, err error) {
obj, err := c.Fake.
Invokes(core.NewRootUpdateAction("componentstatuses", componentStatus), &api.ComponentStatus{})
if obj == nil {
return nil, err
}
return obj.(*api.ComponentStatus), err
}
func (c *FakeComponentStatuses) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewRootDeleteAction("componentstatuses", name), &api.ComponentStatus{})
return err
}
func (c *FakeComponentStatuses) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewRootDeleteCollectionAction("componentstatuses", listOptions)
_, err := c.Fake.Invokes(action, &api.ComponentStatusList{})
return err
}
func (c *FakeComponentStatuses) Get(name string) (result *api.ComponentStatus, err error) {
obj, err := c.Fake.
Invokes(core.NewRootGetAction("componentstatuses", name), &api.ComponentStatus{})
if obj == nil {
return nil, err
}
return obj.(*api.ComponentStatus), err
}
func (c *FakeComponentStatuses) List(opts api.ListOptions) (result *api.ComponentStatusList, err error) {
obj, err := c.Fake.
Invokes(core.NewRootListAction("componentstatuses", opts), &api.ComponentStatusList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.ComponentStatusList{}
for _, item := range obj.(*api.ComponentStatusList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested componentStatuses.
func (c *FakeComponentStatuses) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewRootWatchAction("componentstatuses", opts))
}

View file

@ -1,102 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeConfigMaps implements ConfigMapInterface
type FakeConfigMaps struct {
Fake *FakeCore
ns string
}
func (c *FakeConfigMaps) Create(configMap *api.ConfigMap) (result *api.ConfigMap, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("configmaps", c.ns, configMap), &api.ConfigMap{})
if obj == nil {
return nil, err
}
return obj.(*api.ConfigMap), err
}
func (c *FakeConfigMaps) Update(configMap *api.ConfigMap) (result *api.ConfigMap, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("configmaps", c.ns, configMap), &api.ConfigMap{})
if obj == nil {
return nil, err
}
return obj.(*api.ConfigMap), err
}
func (c *FakeConfigMaps) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("configmaps", c.ns, name), &api.ConfigMap{})
return err
}
func (c *FakeConfigMaps) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("configmaps", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &api.ConfigMapList{})
return err
}
func (c *FakeConfigMaps) Get(name string) (result *api.ConfigMap, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("configmaps", c.ns, name), &api.ConfigMap{})
if obj == nil {
return nil, err
}
return obj.(*api.ConfigMap), err
}
func (c *FakeConfigMaps) List(opts api.ListOptions) (result *api.ConfigMapList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("configmaps", c.ns, opts), &api.ConfigMapList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.ConfigMapList{}
for _, item := range obj.(*api.ConfigMapList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested configMaps.
func (c *FakeConfigMaps) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("configmaps", c.ns, opts))
}

View file

@ -1,90 +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 fake
import (
core "k8s.io/kubernetes/pkg/client/testing/core"
unversioned "k8s.io/kubernetes/pkg/client/typed/generated/core/unversioned"
)
type FakeCore struct {
*core.Fake
}
func (c *FakeCore) ComponentStatuses() unversioned.ComponentStatusInterface {
return &FakeComponentStatuses{c}
}
func (c *FakeCore) ConfigMaps(namespace string) unversioned.ConfigMapInterface {
return &FakeConfigMaps{c, namespace}
}
func (c *FakeCore) Endpoints(namespace string) unversioned.EndpointsInterface {
return &FakeEndpoints{c, namespace}
}
func (c *FakeCore) Events(namespace string) unversioned.EventInterface {
return &FakeEvents{c, namespace}
}
func (c *FakeCore) LimitRanges(namespace string) unversioned.LimitRangeInterface {
return &FakeLimitRanges{c, namespace}
}
func (c *FakeCore) Namespaces() unversioned.NamespaceInterface {
return &FakeNamespaces{c}
}
func (c *FakeCore) Nodes() unversioned.NodeInterface {
return &FakeNodes{c}
}
func (c *FakeCore) PersistentVolumes() unversioned.PersistentVolumeInterface {
return &FakePersistentVolumes{c}
}
func (c *FakeCore) PersistentVolumeClaims(namespace string) unversioned.PersistentVolumeClaimInterface {
return &FakePersistentVolumeClaims{c, namespace}
}
func (c *FakeCore) Pods(namespace string) unversioned.PodInterface {
return &FakePods{c, namespace}
}
func (c *FakeCore) PodTemplates(namespace string) unversioned.PodTemplateInterface {
return &FakePodTemplates{c, namespace}
}
func (c *FakeCore) ReplicationControllers(namespace string) unversioned.ReplicationControllerInterface {
return &FakeReplicationControllers{c, namespace}
}
func (c *FakeCore) ResourceQuotas(namespace string) unversioned.ResourceQuotaInterface {
return &FakeResourceQuotas{c, namespace}
}
func (c *FakeCore) Secrets(namespace string) unversioned.SecretInterface {
return &FakeSecrets{c, namespace}
}
func (c *FakeCore) Services(namespace string) unversioned.ServiceInterface {
return &FakeServices{c, namespace}
}
func (c *FakeCore) ServiceAccounts(namespace string) unversioned.ServiceAccountInterface {
return &FakeServiceAccounts{c, namespace}
}

View file

@ -1,102 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeEndpoints implements EndpointsInterface
type FakeEndpoints struct {
Fake *FakeCore
ns string
}
func (c *FakeEndpoints) Create(endpoints *api.Endpoints) (result *api.Endpoints, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("endpoints", c.ns, endpoints), &api.Endpoints{})
if obj == nil {
return nil, err
}
return obj.(*api.Endpoints), err
}
func (c *FakeEndpoints) Update(endpoints *api.Endpoints) (result *api.Endpoints, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("endpoints", c.ns, endpoints), &api.Endpoints{})
if obj == nil {
return nil, err
}
return obj.(*api.Endpoints), err
}
func (c *FakeEndpoints) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("endpoints", c.ns, name), &api.Endpoints{})
return err
}
func (c *FakeEndpoints) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("endpoints", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &api.EndpointsList{})
return err
}
func (c *FakeEndpoints) Get(name string) (result *api.Endpoints, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("endpoints", c.ns, name), &api.Endpoints{})
if obj == nil {
return nil, err
}
return obj.(*api.Endpoints), err
}
func (c *FakeEndpoints) List(opts api.ListOptions) (result *api.EndpointsList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("endpoints", c.ns, opts), &api.EndpointsList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.EndpointsList{}
for _, item := range obj.(*api.EndpointsList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested endpoints.
func (c *FakeEndpoints) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("endpoints", c.ns, opts))
}

View file

@ -1,102 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeEvents implements EventInterface
type FakeEvents struct {
Fake *FakeCore
ns string
}
func (c *FakeEvents) Create(event *api.Event) (result *api.Event, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("events", c.ns, event), &api.Event{})
if obj == nil {
return nil, err
}
return obj.(*api.Event), err
}
func (c *FakeEvents) Update(event *api.Event) (result *api.Event, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("events", c.ns, event), &api.Event{})
if obj == nil {
return nil, err
}
return obj.(*api.Event), err
}
func (c *FakeEvents) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("events", c.ns, name), &api.Event{})
return err
}
func (c *FakeEvents) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("events", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &api.EventList{})
return err
}
func (c *FakeEvents) Get(name string) (result *api.Event, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("events", c.ns, name), &api.Event{})
if obj == nil {
return nil, err
}
return obj.(*api.Event), err
}
func (c *FakeEvents) List(opts api.ListOptions) (result *api.EventList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("events", c.ns, opts), &api.EventList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.EventList{}
for _, item := range obj.(*api.EventList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested events.
func (c *FakeEvents) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("events", c.ns, opts))
}

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 fake
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/testing/core"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/runtime"
)
func (c *FakeEvents) CreateWithEventNamespace(event *api.Event) (*api.Event, error) {
action := core.NewRootCreateAction("events", event)
if c.ns != "" {
action = core.NewCreateAction("events", c.ns, event)
}
obj, err := c.Fake.Invokes(action, event)
if obj == nil {
return nil, err
}
return obj.(*api.Event), err
}
// Update replaces an existing event. Returns the copy of the event the server returns, or an error.
func (c *FakeEvents) UpdateWithEventNamespace(event *api.Event) (*api.Event, error) {
action := core.NewRootUpdateAction("events", event)
if c.ns != "" {
action = core.NewUpdateAction("events", c.ns, event)
}
obj, err := c.Fake.Invokes(action, event)
if obj == nil {
return nil, err
}
return obj.(*api.Event), err
}
// Patch patches an existing event. Returns the copy of the event the server returns, or an error.
func (c *FakeEvents) Patch(event *api.Event, data []byte) (*api.Event, error) {
action := core.NewRootPatchAction("events", event)
if c.ns != "" {
action = core.NewPatchAction("events", c.ns, event)
}
obj, err := c.Fake.Invokes(action, event)
if obj == nil {
return nil, err
}
return obj.(*api.Event), err
}
// Search returns a list of events matching the specified object.
func (c *FakeEvents) Search(objOrRef runtime.Object) (*api.EventList, error) {
action := core.NewRootListAction("events", api.ListOptions{})
if c.ns != "" {
action = core.NewListAction("events", c.ns, api.ListOptions{})
}
obj, err := c.Fake.Invokes(action, &api.EventList{})
if obj == nil {
return nil, err
}
return obj.(*api.EventList), err
}
func (c *FakeEvents) GetFieldSelector(involvedObjectName, involvedObjectNamespace, involvedObjectKind, involvedObjectUID *string) fields.Selector {
action := core.GenericActionImpl{}
action.Verb = "get-field-selector"
action.Resource = "events"
c.Fake.Invokes(action, nil)
return fields.Everything()
}

View file

@ -1,102 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeLimitRanges implements LimitRangeInterface
type FakeLimitRanges struct {
Fake *FakeCore
ns string
}
func (c *FakeLimitRanges) Create(limitRange *api.LimitRange) (result *api.LimitRange, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("limitranges", c.ns, limitRange), &api.LimitRange{})
if obj == nil {
return nil, err
}
return obj.(*api.LimitRange), err
}
func (c *FakeLimitRanges) Update(limitRange *api.LimitRange) (result *api.LimitRange, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("limitranges", c.ns, limitRange), &api.LimitRange{})
if obj == nil {
return nil, err
}
return obj.(*api.LimitRange), err
}
func (c *FakeLimitRanges) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("limitranges", c.ns, name), &api.LimitRange{})
return err
}
func (c *FakeLimitRanges) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("limitranges", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &api.LimitRangeList{})
return err
}
func (c *FakeLimitRanges) Get(name string) (result *api.LimitRange, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("limitranges", c.ns, name), &api.LimitRange{})
if obj == nil {
return nil, err
}
return obj.(*api.LimitRange), err
}
func (c *FakeLimitRanges) List(opts api.ListOptions) (result *api.LimitRangeList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("limitranges", c.ns, opts), &api.LimitRangeList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.LimitRangeList{}
for _, item := range obj.(*api.LimitRangeList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested limitRanges.
func (c *FakeLimitRanges) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("limitranges", c.ns, opts))
}

View file

@ -1,104 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeNamespaces implements NamespaceInterface
type FakeNamespaces struct {
Fake *FakeCore
}
func (c *FakeNamespaces) Create(namespace *api.Namespace) (result *api.Namespace, err error) {
obj, err := c.Fake.
Invokes(core.NewRootCreateAction("namespaces", namespace), &api.Namespace{})
if obj == nil {
return nil, err
}
return obj.(*api.Namespace), err
}
func (c *FakeNamespaces) Update(namespace *api.Namespace) (result *api.Namespace, err error) {
obj, err := c.Fake.
Invokes(core.NewRootUpdateAction("namespaces", namespace), &api.Namespace{})
if obj == nil {
return nil, err
}
return obj.(*api.Namespace), err
}
func (c *FakeNamespaces) UpdateStatus(namespace *api.Namespace) (*api.Namespace, error) {
obj, err := c.Fake.
Invokes(core.NewRootUpdateSubresourceAction("namespaces", "status", namespace), &api.Namespace{})
if obj == nil {
return nil, err
}
return obj.(*api.Namespace), err
}
func (c *FakeNamespaces) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewRootDeleteAction("namespaces", name), &api.Namespace{})
return err
}
func (c *FakeNamespaces) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewRootDeleteCollectionAction("namespaces", listOptions)
_, err := c.Fake.Invokes(action, &api.NamespaceList{})
return err
}
func (c *FakeNamespaces) Get(name string) (result *api.Namespace, err error) {
obj, err := c.Fake.
Invokes(core.NewRootGetAction("namespaces", name), &api.Namespace{})
if obj == nil {
return nil, err
}
return obj.(*api.Namespace), err
}
func (c *FakeNamespaces) List(opts api.ListOptions) (result *api.NamespaceList, err error) {
obj, err := c.Fake.
Invokes(core.NewRootListAction("namespaces", opts), &api.NamespaceList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.NamespaceList{}
for _, item := range obj.(*api.NamespaceList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested namespaces.
func (c *FakeNamespaces) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewRootWatchAction("namespaces", opts))
}

View file

@ -1,37 +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 fake
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/testing/core"
)
func (c *FakeNamespaces) Finalize(namespace *api.Namespace) (*api.Namespace, error) {
action := core.CreateActionImpl{}
action.Verb = "create"
action.Resource = "namespaces"
action.Subresource = "finalize"
action.Object = namespace
obj, err := c.Fake.Invokes(action, namespace)
if obj == nil {
return nil, err
}
return obj.(*api.Namespace), err
}

View file

@ -1,104 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeNodes implements NodeInterface
type FakeNodes struct {
Fake *FakeCore
}
func (c *FakeNodes) Create(node *api.Node) (result *api.Node, err error) {
obj, err := c.Fake.
Invokes(core.NewRootCreateAction("nodes", node), &api.Node{})
if obj == nil {
return nil, err
}
return obj.(*api.Node), err
}
func (c *FakeNodes) Update(node *api.Node) (result *api.Node, err error) {
obj, err := c.Fake.
Invokes(core.NewRootUpdateAction("nodes", node), &api.Node{})
if obj == nil {
return nil, err
}
return obj.(*api.Node), err
}
func (c *FakeNodes) UpdateStatus(node *api.Node) (*api.Node, error) {
obj, err := c.Fake.
Invokes(core.NewRootUpdateSubresourceAction("nodes", "status", node), &api.Node{})
if obj == nil {
return nil, err
}
return obj.(*api.Node), err
}
func (c *FakeNodes) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewRootDeleteAction("nodes", name), &api.Node{})
return err
}
func (c *FakeNodes) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewRootDeleteCollectionAction("nodes", listOptions)
_, err := c.Fake.Invokes(action, &api.NodeList{})
return err
}
func (c *FakeNodes) Get(name string) (result *api.Node, err error) {
obj, err := c.Fake.
Invokes(core.NewRootGetAction("nodes", name), &api.Node{})
if obj == nil {
return nil, err
}
return obj.(*api.Node), err
}
func (c *FakeNodes) List(opts api.ListOptions) (result *api.NodeList, err error) {
obj, err := c.Fake.
Invokes(core.NewRootListAction("nodes", opts), &api.NodeList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.NodeList{}
for _, item := range obj.(*api.NodeList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested nodes.
func (c *FakeNodes) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewRootWatchAction("nodes", opts))
}

View file

@ -1,104 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakePersistentVolumes implements PersistentVolumeInterface
type FakePersistentVolumes struct {
Fake *FakeCore
}
func (c *FakePersistentVolumes) Create(persistentVolume *api.PersistentVolume) (result *api.PersistentVolume, err error) {
obj, err := c.Fake.
Invokes(core.NewRootCreateAction("persistentvolumes", persistentVolume), &api.PersistentVolume{})
if obj == nil {
return nil, err
}
return obj.(*api.PersistentVolume), err
}
func (c *FakePersistentVolumes) Update(persistentVolume *api.PersistentVolume) (result *api.PersistentVolume, err error) {
obj, err := c.Fake.
Invokes(core.NewRootUpdateAction("persistentvolumes", persistentVolume), &api.PersistentVolume{})
if obj == nil {
return nil, err
}
return obj.(*api.PersistentVolume), err
}
func (c *FakePersistentVolumes) UpdateStatus(persistentVolume *api.PersistentVolume) (*api.PersistentVolume, error) {
obj, err := c.Fake.
Invokes(core.NewRootUpdateSubresourceAction("persistentvolumes", "status", persistentVolume), &api.PersistentVolume{})
if obj == nil {
return nil, err
}
return obj.(*api.PersistentVolume), err
}
func (c *FakePersistentVolumes) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewRootDeleteAction("persistentvolumes", name), &api.PersistentVolume{})
return err
}
func (c *FakePersistentVolumes) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewRootDeleteCollectionAction("persistentvolumes", listOptions)
_, err := c.Fake.Invokes(action, &api.PersistentVolumeList{})
return err
}
func (c *FakePersistentVolumes) Get(name string) (result *api.PersistentVolume, err error) {
obj, err := c.Fake.
Invokes(core.NewRootGetAction("persistentvolumes", name), &api.PersistentVolume{})
if obj == nil {
return nil, err
}
return obj.(*api.PersistentVolume), err
}
func (c *FakePersistentVolumes) List(opts api.ListOptions) (result *api.PersistentVolumeList, err error) {
obj, err := c.Fake.
Invokes(core.NewRootListAction("persistentvolumes", opts), &api.PersistentVolumeList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.PersistentVolumeList{}
for _, item := range obj.(*api.PersistentVolumeList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested persistentVolumes.
func (c *FakePersistentVolumes) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewRootWatchAction("persistentvolumes", opts))
}

View file

@ -1,112 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakePersistentVolumeClaims implements PersistentVolumeClaimInterface
type FakePersistentVolumeClaims struct {
Fake *FakeCore
ns string
}
func (c *FakePersistentVolumeClaims) Create(persistentVolumeClaim *api.PersistentVolumeClaim) (result *api.PersistentVolumeClaim, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("persistentvolumeclaims", c.ns, persistentVolumeClaim), &api.PersistentVolumeClaim{})
if obj == nil {
return nil, err
}
return obj.(*api.PersistentVolumeClaim), err
}
func (c *FakePersistentVolumeClaims) Update(persistentVolumeClaim *api.PersistentVolumeClaim) (result *api.PersistentVolumeClaim, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("persistentvolumeclaims", c.ns, persistentVolumeClaim), &api.PersistentVolumeClaim{})
if obj == nil {
return nil, err
}
return obj.(*api.PersistentVolumeClaim), err
}
func (c *FakePersistentVolumeClaims) UpdateStatus(persistentVolumeClaim *api.PersistentVolumeClaim) (*api.PersistentVolumeClaim, error) {
obj, err := c.Fake.
Invokes(core.NewUpdateSubresourceAction("persistentvolumeclaims", "status", c.ns, persistentVolumeClaim), &api.PersistentVolumeClaim{})
if obj == nil {
return nil, err
}
return obj.(*api.PersistentVolumeClaim), err
}
func (c *FakePersistentVolumeClaims) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("persistentvolumeclaims", c.ns, name), &api.PersistentVolumeClaim{})
return err
}
func (c *FakePersistentVolumeClaims) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("persistentvolumeclaims", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &api.PersistentVolumeClaimList{})
return err
}
func (c *FakePersistentVolumeClaims) Get(name string) (result *api.PersistentVolumeClaim, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("persistentvolumeclaims", c.ns, name), &api.PersistentVolumeClaim{})
if obj == nil {
return nil, err
}
return obj.(*api.PersistentVolumeClaim), err
}
func (c *FakePersistentVolumeClaims) List(opts api.ListOptions) (result *api.PersistentVolumeClaimList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("persistentvolumeclaims", c.ns, opts), &api.PersistentVolumeClaimList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.PersistentVolumeClaimList{}
for _, item := range obj.(*api.PersistentVolumeClaimList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested persistentVolumeClaims.
func (c *FakePersistentVolumeClaims) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("persistentvolumeclaims", c.ns, opts))
}

View file

@ -1,112 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakePods implements PodInterface
type FakePods struct {
Fake *FakeCore
ns string
}
func (c *FakePods) Create(pod *api.Pod) (result *api.Pod, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("pods", c.ns, pod), &api.Pod{})
if obj == nil {
return nil, err
}
return obj.(*api.Pod), err
}
func (c *FakePods) Update(pod *api.Pod) (result *api.Pod, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("pods", c.ns, pod), &api.Pod{})
if obj == nil {
return nil, err
}
return obj.(*api.Pod), err
}
func (c *FakePods) UpdateStatus(pod *api.Pod) (*api.Pod, error) {
obj, err := c.Fake.
Invokes(core.NewUpdateSubresourceAction("pods", "status", c.ns, pod), &api.Pod{})
if obj == nil {
return nil, err
}
return obj.(*api.Pod), err
}
func (c *FakePods) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("pods", c.ns, name), &api.Pod{})
return err
}
func (c *FakePods) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("pods", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &api.PodList{})
return err
}
func (c *FakePods) Get(name string) (result *api.Pod, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("pods", c.ns, name), &api.Pod{})
if obj == nil {
return nil, err
}
return obj.(*api.Pod), err
}
func (c *FakePods) List(opts api.ListOptions) (result *api.PodList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("pods", c.ns, opts), &api.PodList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.PodList{}
for _, item := range obj.(*api.PodList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested pods.
func (c *FakePods) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("pods", c.ns, opts))
}

View file

@ -1,46 +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 fake
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/testing/core"
client "k8s.io/kubernetes/pkg/client/unversioned"
)
func (c *FakePods) Bind(binding *api.Binding) error {
action := core.CreateActionImpl{}
action.Verb = "create"
action.Resource = "pods"
action.Subresource = "bindings"
action.Object = binding
_, err := c.Fake.Invokes(action, binding)
return err
}
func (c *FakePods) GetLogs(name string, opts *api.PodLogOptions) *client.Request {
action := core.GenericActionImpl{}
action.Verb = "get"
action.Namespace = c.ns
action.Resource = "pod"
action.Subresource = "logs"
action.Value = opts
_, _ = c.Fake.Invokes(action, &api.Pod{})
return &client.Request{}
}

View file

@ -1,102 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakePodTemplates implements PodTemplateInterface
type FakePodTemplates struct {
Fake *FakeCore
ns string
}
func (c *FakePodTemplates) Create(podTemplate *api.PodTemplate) (result *api.PodTemplate, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("podtemplates", c.ns, podTemplate), &api.PodTemplate{})
if obj == nil {
return nil, err
}
return obj.(*api.PodTemplate), err
}
func (c *FakePodTemplates) Update(podTemplate *api.PodTemplate) (result *api.PodTemplate, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("podtemplates", c.ns, podTemplate), &api.PodTemplate{})
if obj == nil {
return nil, err
}
return obj.(*api.PodTemplate), err
}
func (c *FakePodTemplates) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("podtemplates", c.ns, name), &api.PodTemplate{})
return err
}
func (c *FakePodTemplates) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("podtemplates", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &api.PodTemplateList{})
return err
}
func (c *FakePodTemplates) Get(name string) (result *api.PodTemplate, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("podtemplates", c.ns, name), &api.PodTemplate{})
if obj == nil {
return nil, err
}
return obj.(*api.PodTemplate), err
}
func (c *FakePodTemplates) List(opts api.ListOptions) (result *api.PodTemplateList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("podtemplates", c.ns, opts), &api.PodTemplateList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.PodTemplateList{}
for _, item := range obj.(*api.PodTemplateList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested podTemplates.
func (c *FakePodTemplates) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("podtemplates", c.ns, opts))
}

View file

@ -1,112 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeReplicationControllers implements ReplicationControllerInterface
type FakeReplicationControllers struct {
Fake *FakeCore
ns string
}
func (c *FakeReplicationControllers) Create(replicationController *api.ReplicationController) (result *api.ReplicationController, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("replicationcontrollers", c.ns, replicationController), &api.ReplicationController{})
if obj == nil {
return nil, err
}
return obj.(*api.ReplicationController), err
}
func (c *FakeReplicationControllers) Update(replicationController *api.ReplicationController) (result *api.ReplicationController, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("replicationcontrollers", c.ns, replicationController), &api.ReplicationController{})
if obj == nil {
return nil, err
}
return obj.(*api.ReplicationController), err
}
func (c *FakeReplicationControllers) UpdateStatus(replicationController *api.ReplicationController) (*api.ReplicationController, error) {
obj, err := c.Fake.
Invokes(core.NewUpdateSubresourceAction("replicationcontrollers", "status", c.ns, replicationController), &api.ReplicationController{})
if obj == nil {
return nil, err
}
return obj.(*api.ReplicationController), err
}
func (c *FakeReplicationControllers) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("replicationcontrollers", c.ns, name), &api.ReplicationController{})
return err
}
func (c *FakeReplicationControllers) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("replicationcontrollers", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &api.ReplicationControllerList{})
return err
}
func (c *FakeReplicationControllers) Get(name string) (result *api.ReplicationController, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("replicationcontrollers", c.ns, name), &api.ReplicationController{})
if obj == nil {
return nil, err
}
return obj.(*api.ReplicationController), err
}
func (c *FakeReplicationControllers) List(opts api.ListOptions) (result *api.ReplicationControllerList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("replicationcontrollers", c.ns, opts), &api.ReplicationControllerList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.ReplicationControllerList{}
for _, item := range obj.(*api.ReplicationControllerList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested replicationControllers.
func (c *FakeReplicationControllers) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("replicationcontrollers", c.ns, opts))
}

View file

@ -1,112 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeResourceQuotas implements ResourceQuotaInterface
type FakeResourceQuotas struct {
Fake *FakeCore
ns string
}
func (c *FakeResourceQuotas) Create(resourceQuota *api.ResourceQuota) (result *api.ResourceQuota, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("resourcequotas", c.ns, resourceQuota), &api.ResourceQuota{})
if obj == nil {
return nil, err
}
return obj.(*api.ResourceQuota), err
}
func (c *FakeResourceQuotas) Update(resourceQuota *api.ResourceQuota) (result *api.ResourceQuota, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("resourcequotas", c.ns, resourceQuota), &api.ResourceQuota{})
if obj == nil {
return nil, err
}
return obj.(*api.ResourceQuota), err
}
func (c *FakeResourceQuotas) UpdateStatus(resourceQuota *api.ResourceQuota) (*api.ResourceQuota, error) {
obj, err := c.Fake.
Invokes(core.NewUpdateSubresourceAction("resourcequotas", "status", c.ns, resourceQuota), &api.ResourceQuota{})
if obj == nil {
return nil, err
}
return obj.(*api.ResourceQuota), err
}
func (c *FakeResourceQuotas) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("resourcequotas", c.ns, name), &api.ResourceQuota{})
return err
}
func (c *FakeResourceQuotas) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("resourcequotas", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &api.ResourceQuotaList{})
return err
}
func (c *FakeResourceQuotas) Get(name string) (result *api.ResourceQuota, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("resourcequotas", c.ns, name), &api.ResourceQuota{})
if obj == nil {
return nil, err
}
return obj.(*api.ResourceQuota), err
}
func (c *FakeResourceQuotas) List(opts api.ListOptions) (result *api.ResourceQuotaList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("resourcequotas", c.ns, opts), &api.ResourceQuotaList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.ResourceQuotaList{}
for _, item := range obj.(*api.ResourceQuotaList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested resourceQuotas.
func (c *FakeResourceQuotas) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("resourcequotas", c.ns, opts))
}

View file

@ -1,102 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeSecrets implements SecretInterface
type FakeSecrets struct {
Fake *FakeCore
ns string
}
func (c *FakeSecrets) Create(secret *api.Secret) (result *api.Secret, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("secrets", c.ns, secret), &api.Secret{})
if obj == nil {
return nil, err
}
return obj.(*api.Secret), err
}
func (c *FakeSecrets) Update(secret *api.Secret) (result *api.Secret, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("secrets", c.ns, secret), &api.Secret{})
if obj == nil {
return nil, err
}
return obj.(*api.Secret), err
}
func (c *FakeSecrets) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("secrets", c.ns, name), &api.Secret{})
return err
}
func (c *FakeSecrets) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("secrets", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &api.SecretList{})
return err
}
func (c *FakeSecrets) Get(name string) (result *api.Secret, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("secrets", c.ns, name), &api.Secret{})
if obj == nil {
return nil, err
}
return obj.(*api.Secret), err
}
func (c *FakeSecrets) List(opts api.ListOptions) (result *api.SecretList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("secrets", c.ns, opts), &api.SecretList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.SecretList{}
for _, item := range obj.(*api.SecretList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested secrets.
func (c *FakeSecrets) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("secrets", c.ns, opts))
}

View file

@ -1,112 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeServices implements ServiceInterface
type FakeServices struct {
Fake *FakeCore
ns string
}
func (c *FakeServices) Create(service *api.Service) (result *api.Service, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("services", c.ns, service), &api.Service{})
if obj == nil {
return nil, err
}
return obj.(*api.Service), err
}
func (c *FakeServices) Update(service *api.Service) (result *api.Service, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("services", c.ns, service), &api.Service{})
if obj == nil {
return nil, err
}
return obj.(*api.Service), err
}
func (c *FakeServices) UpdateStatus(service *api.Service) (*api.Service, error) {
obj, err := c.Fake.
Invokes(core.NewUpdateSubresourceAction("services", "status", c.ns, service), &api.Service{})
if obj == nil {
return nil, err
}
return obj.(*api.Service), err
}
func (c *FakeServices) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("services", c.ns, name), &api.Service{})
return err
}
func (c *FakeServices) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("services", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &api.ServiceList{})
return err
}
func (c *FakeServices) Get(name string) (result *api.Service, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("services", c.ns, name), &api.Service{})
if obj == nil {
return nil, err
}
return obj.(*api.Service), err
}
func (c *FakeServices) List(opts api.ListOptions) (result *api.ServiceList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("services", c.ns, opts), &api.ServiceList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.ServiceList{}
for _, item := range obj.(*api.ServiceList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested services.
func (c *FakeServices) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("services", c.ns, opts))
}

View file

@ -1,26 +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 fake
import (
"k8s.io/kubernetes/pkg/client/testing/core"
client "k8s.io/kubernetes/pkg/client/unversioned"
)
func (c *FakeServices) ProxyGet(scheme, name, port, path string, params map[string]string) client.ResponseWrapper {
return c.Fake.InvokesProxy(core.NewProxyGetAction("services", c.ns, scheme, name, port, path, params))
}

View file

@ -1,102 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeServiceAccounts implements ServiceAccountInterface
type FakeServiceAccounts struct {
Fake *FakeCore
ns string
}
func (c *FakeServiceAccounts) Create(serviceAccount *api.ServiceAccount) (result *api.ServiceAccount, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("serviceaccounts", c.ns, serviceAccount), &api.ServiceAccount{})
if obj == nil {
return nil, err
}
return obj.(*api.ServiceAccount), err
}
func (c *FakeServiceAccounts) Update(serviceAccount *api.ServiceAccount) (result *api.ServiceAccount, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("serviceaccounts", c.ns, serviceAccount), &api.ServiceAccount{})
if obj == nil {
return nil, err
}
return obj.(*api.ServiceAccount), err
}
func (c *FakeServiceAccounts) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("serviceaccounts", c.ns, name), &api.ServiceAccount{})
return err
}
func (c *FakeServiceAccounts) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("serviceaccounts", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &api.ServiceAccountList{})
return err
}
func (c *FakeServiceAccounts) Get(name string) (result *api.ServiceAccount, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("serviceaccounts", c.ns, name), &api.ServiceAccount{})
if obj == nil {
return nil, err
}
return obj.(*api.ServiceAccount), err
}
func (c *FakeServiceAccounts) List(opts api.ListOptions) (result *api.ServiceAccountList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("serviceaccounts", c.ns, opts), &api.ServiceAccountList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &api.ServiceAccountList{}
for _, item := range obj.(*api.ServiceAccountList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested serviceAccounts.
func (c *FakeServiceAccounts) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("serviceaccounts", c.ns, opts))
}

View file

@ -18,13 +18,13 @@ package unversioned
import (
"k8s.io/kubernetes/pkg/api"
unversioned "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/restclient"
)
// The PodExpansion interface allows manually adding extra methods to the PodInterface.
type PodExpansion interface {
Bind(binding *api.Binding) error
GetLogs(name string, opts *api.PodLogOptions) *unversioned.Request
GetLogs(name string, opts *api.PodLogOptions) *restclient.Request
}
// Bind applies the provided binding to the named pod in the current namespace (binding.Namespace is ignored).
@ -33,6 +33,6 @@ func (c *pods) Bind(binding *api.Binding) error {
}
// Get constructs a request for getting the logs for a pod
func (c *pods) GetLogs(name string, opts *api.PodLogOptions) *unversioned.Request {
func (c *pods) GetLogs(name string, opts *api.PodLogOptions) *restclient.Request {
return c.client.Get().Namespace(c.ns).Name(name).Resource("pods").SubResource("log").VersionedParams(opts, api.ParameterCodec)
}

View file

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

View file

@ -19,7 +19,7 @@ package unversioned
import (
api "k8s.io/kubernetes/pkg/api"
registered "k8s.io/kubernetes/pkg/apimachinery/registered"
unversioned "k8s.io/kubernetes/pkg/client/unversioned"
restclient "k8s.io/kubernetes/pkg/client/restclient"
)
type ExtensionsInterface interface {
@ -35,7 +35,7 @@ type ExtensionsInterface interface {
// ExtensionsClient is used to interact with features provided by the Extensions group.
type ExtensionsClient struct {
*unversioned.RESTClient
*restclient.RESTClient
}
func (c *ExtensionsClient) DaemonSets(namespace string) DaemonSetInterface {
@ -71,12 +71,12 @@ func (c *ExtensionsClient) ThirdPartyResources(namespace string) ThirdPartyResou
}
// NewForConfig creates a new ExtensionsClient for the given config.
func NewForConfig(c *unversioned.Config) (*ExtensionsClient, error) {
func NewForConfig(c *restclient.Config) (*ExtensionsClient, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
}
client, err := unversioned.RESTClientFor(&config)
client, err := restclient.RESTClientFor(&config)
if err != nil {
return nil, err
}
@ -85,7 +85,7 @@ func NewForConfig(c *unversioned.Config) (*ExtensionsClient, error) {
// NewForConfigOrDie creates a new ExtensionsClient for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *unversioned.Config) *ExtensionsClient {
func NewForConfigOrDie(c *restclient.Config) *ExtensionsClient {
client, err := NewForConfig(c)
if err != nil {
panic(err)
@ -94,11 +94,11 @@ func NewForConfigOrDie(c *unversioned.Config) *ExtensionsClient {
}
// New creates a new ExtensionsClient for the given RESTClient.
func New(c *unversioned.RESTClient) *ExtensionsClient {
func New(c *restclient.RESTClient) *ExtensionsClient {
return &ExtensionsClient{c}
}
func setConfigDefaults(config *unversioned.Config) error {
func setConfigDefaults(config *restclient.Config) error {
// if extensions group is not registered, return an error
g, err := registered.Group("extensions")
if err != nil {
@ -106,7 +106,7 @@ func setConfigDefaults(config *unversioned.Config) error {
}
config.APIPath = "/apis"
if config.UserAgent == "" {
config.UserAgent = unversioned.DefaultKubernetesUserAgent()
config.UserAgent = restclient.DefaultKubernetesUserAgent()
}
// TODO: Unconditionally set the config.Version, until we fix the config.
//if config.Version == "" {

View file

@ -1,18 +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 fake has the automatically generated clients.
package fake

View file

@ -1,113 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeDaemonSets implements DaemonSetInterface
type FakeDaemonSets struct {
Fake *FakeExtensions
ns string
}
func (c *FakeDaemonSets) Create(daemonSet *extensions.DaemonSet) (result *extensions.DaemonSet, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("daemonsets", c.ns, daemonSet), &extensions.DaemonSet{})
if obj == nil {
return nil, err
}
return obj.(*extensions.DaemonSet), err
}
func (c *FakeDaemonSets) Update(daemonSet *extensions.DaemonSet) (result *extensions.DaemonSet, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("daemonsets", c.ns, daemonSet), &extensions.DaemonSet{})
if obj == nil {
return nil, err
}
return obj.(*extensions.DaemonSet), err
}
func (c *FakeDaemonSets) UpdateStatus(daemonSet *extensions.DaemonSet) (*extensions.DaemonSet, error) {
obj, err := c.Fake.
Invokes(core.NewUpdateSubresourceAction("daemonsets", "status", c.ns, daemonSet), &extensions.DaemonSet{})
if obj == nil {
return nil, err
}
return obj.(*extensions.DaemonSet), err
}
func (c *FakeDaemonSets) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("daemonsets", c.ns, name), &extensions.DaemonSet{})
return err
}
func (c *FakeDaemonSets) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("daemonsets", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &extensions.DaemonSetList{})
return err
}
func (c *FakeDaemonSets) Get(name string) (result *extensions.DaemonSet, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("daemonsets", c.ns, name), &extensions.DaemonSet{})
if obj == nil {
return nil, err
}
return obj.(*extensions.DaemonSet), err
}
func (c *FakeDaemonSets) List(opts api.ListOptions) (result *extensions.DaemonSetList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("daemonsets", c.ns, opts), &extensions.DaemonSetList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &extensions.DaemonSetList{}
for _, item := range obj.(*extensions.DaemonSetList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested daemonSets.
func (c *FakeDaemonSets) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("daemonsets", c.ns, opts))
}

View file

@ -1,113 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeDeployments implements DeploymentInterface
type FakeDeployments struct {
Fake *FakeExtensions
ns string
}
func (c *FakeDeployments) Create(deployment *extensions.Deployment) (result *extensions.Deployment, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("deployments", c.ns, deployment), &extensions.Deployment{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Deployment), err
}
func (c *FakeDeployments) Update(deployment *extensions.Deployment) (result *extensions.Deployment, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("deployments", c.ns, deployment), &extensions.Deployment{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Deployment), err
}
func (c *FakeDeployments) UpdateStatus(deployment *extensions.Deployment) (*extensions.Deployment, error) {
obj, err := c.Fake.
Invokes(core.NewUpdateSubresourceAction("deployments", "status", c.ns, deployment), &extensions.Deployment{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Deployment), err
}
func (c *FakeDeployments) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("deployments", c.ns, name), &extensions.Deployment{})
return err
}
func (c *FakeDeployments) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("deployments", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &extensions.DeploymentList{})
return err
}
func (c *FakeDeployments) Get(name string) (result *extensions.Deployment, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("deployments", c.ns, name), &extensions.Deployment{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Deployment), err
}
func (c *FakeDeployments) List(opts api.ListOptions) (result *extensions.DeploymentList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("deployments", c.ns, opts), &extensions.DeploymentList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &extensions.DeploymentList{}
for _, item := range obj.(*extensions.DeploymentList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested deployments.
func (c *FakeDeployments) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("deployments", c.ns, opts))
}

View file

@ -1,33 +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 fake
import (
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/testing/core"
)
func (c *FakeDeployments) Rollback(deploymentRollback *extensions.DeploymentRollback) error {
action := core.CreateActionImpl{}
action.Verb = "create"
action.Resource = "deployments"
action.Subresource = "rollback"
action.Object = deploymentRollback
_, err := c.Fake.Invokes(action, deploymentRollback)
return err
}

View file

@ -1,58 +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 fake
import (
core "k8s.io/kubernetes/pkg/client/testing/core"
unversioned "k8s.io/kubernetes/pkg/client/typed/generated/extensions/unversioned"
)
type FakeExtensions struct {
*core.Fake
}
func (c *FakeExtensions) DaemonSets(namespace string) unversioned.DaemonSetInterface {
return &FakeDaemonSets{c, namespace}
}
func (c *FakeExtensions) Deployments(namespace string) unversioned.DeploymentInterface {
return &FakeDeployments{c, namespace}
}
func (c *FakeExtensions) HorizontalPodAutoscalers(namespace string) unversioned.HorizontalPodAutoscalerInterface {
return &FakeHorizontalPodAutoscalers{c, namespace}
}
func (c *FakeExtensions) Ingresses(namespace string) unversioned.IngressInterface {
return &FakeIngresses{c, namespace}
}
func (c *FakeExtensions) Jobs(namespace string) unversioned.JobInterface {
return &FakeJobs{c, namespace}
}
func (c *FakeExtensions) ReplicaSets(namespace string) unversioned.ReplicaSetInterface {
return &FakeReplicaSets{c, namespace}
}
func (c *FakeExtensions) Scales(namespace string) unversioned.ScaleInterface {
return &FakeScales{c, namespace}
}
func (c *FakeExtensions) ThirdPartyResources(namespace string) unversioned.ThirdPartyResourceInterface {
return &FakeThirdPartyResources{c, namespace}
}

View file

@ -1,113 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeHorizontalPodAutoscalers implements HorizontalPodAutoscalerInterface
type FakeHorizontalPodAutoscalers struct {
Fake *FakeExtensions
ns string
}
func (c *FakeHorizontalPodAutoscalers) Create(horizontalPodAutoscaler *extensions.HorizontalPodAutoscaler) (result *extensions.HorizontalPodAutoscaler, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("horizontalpodautoscalers", c.ns, horizontalPodAutoscaler), &extensions.HorizontalPodAutoscaler{})
if obj == nil {
return nil, err
}
return obj.(*extensions.HorizontalPodAutoscaler), err
}
func (c *FakeHorizontalPodAutoscalers) Update(horizontalPodAutoscaler *extensions.HorizontalPodAutoscaler) (result *extensions.HorizontalPodAutoscaler, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("horizontalpodautoscalers", c.ns, horizontalPodAutoscaler), &extensions.HorizontalPodAutoscaler{})
if obj == nil {
return nil, err
}
return obj.(*extensions.HorizontalPodAutoscaler), err
}
func (c *FakeHorizontalPodAutoscalers) UpdateStatus(horizontalPodAutoscaler *extensions.HorizontalPodAutoscaler) (*extensions.HorizontalPodAutoscaler, error) {
obj, err := c.Fake.
Invokes(core.NewUpdateSubresourceAction("horizontalpodautoscalers", "status", c.ns, horizontalPodAutoscaler), &extensions.HorizontalPodAutoscaler{})
if obj == nil {
return nil, err
}
return obj.(*extensions.HorizontalPodAutoscaler), err
}
func (c *FakeHorizontalPodAutoscalers) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("horizontalpodautoscalers", c.ns, name), &extensions.HorizontalPodAutoscaler{})
return err
}
func (c *FakeHorizontalPodAutoscalers) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("horizontalpodautoscalers", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &extensions.HorizontalPodAutoscalerList{})
return err
}
func (c *FakeHorizontalPodAutoscalers) Get(name string) (result *extensions.HorizontalPodAutoscaler, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("horizontalpodautoscalers", c.ns, name), &extensions.HorizontalPodAutoscaler{})
if obj == nil {
return nil, err
}
return obj.(*extensions.HorizontalPodAutoscaler), err
}
func (c *FakeHorizontalPodAutoscalers) List(opts api.ListOptions) (result *extensions.HorizontalPodAutoscalerList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("horizontalpodautoscalers", c.ns, opts), &extensions.HorizontalPodAutoscalerList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &extensions.HorizontalPodAutoscalerList{}
for _, item := range obj.(*extensions.HorizontalPodAutoscalerList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested horizontalPodAutoscalers.
func (c *FakeHorizontalPodAutoscalers) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("horizontalpodautoscalers", c.ns, opts))
}

View file

@ -1,113 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeIngresses implements IngressInterface
type FakeIngresses struct {
Fake *FakeExtensions
ns string
}
func (c *FakeIngresses) Create(ingress *extensions.Ingress) (result *extensions.Ingress, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("ingresses", c.ns, ingress), &extensions.Ingress{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Ingress), err
}
func (c *FakeIngresses) Update(ingress *extensions.Ingress) (result *extensions.Ingress, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("ingresses", c.ns, ingress), &extensions.Ingress{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Ingress), err
}
func (c *FakeIngresses) UpdateStatus(ingress *extensions.Ingress) (*extensions.Ingress, error) {
obj, err := c.Fake.
Invokes(core.NewUpdateSubresourceAction("ingresses", "status", c.ns, ingress), &extensions.Ingress{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Ingress), err
}
func (c *FakeIngresses) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("ingresses", c.ns, name), &extensions.Ingress{})
return err
}
func (c *FakeIngresses) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("ingresses", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &extensions.IngressList{})
return err
}
func (c *FakeIngresses) Get(name string) (result *extensions.Ingress, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("ingresses", c.ns, name), &extensions.Ingress{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Ingress), err
}
func (c *FakeIngresses) List(opts api.ListOptions) (result *extensions.IngressList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("ingresses", c.ns, opts), &extensions.IngressList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &extensions.IngressList{}
for _, item := range obj.(*extensions.IngressList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested ingresses.
func (c *FakeIngresses) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("ingresses", c.ns, opts))
}

View file

@ -1,113 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeJobs implements JobInterface
type FakeJobs struct {
Fake *FakeExtensions
ns string
}
func (c *FakeJobs) Create(job *extensions.Job) (result *extensions.Job, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("jobs", c.ns, job), &extensions.Job{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Job), err
}
func (c *FakeJobs) Update(job *extensions.Job) (result *extensions.Job, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("jobs", c.ns, job), &extensions.Job{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Job), err
}
func (c *FakeJobs) UpdateStatus(job *extensions.Job) (*extensions.Job, error) {
obj, err := c.Fake.
Invokes(core.NewUpdateSubresourceAction("jobs", "status", c.ns, job), &extensions.Job{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Job), err
}
func (c *FakeJobs) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("jobs", c.ns, name), &extensions.Job{})
return err
}
func (c *FakeJobs) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("jobs", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &extensions.JobList{})
return err
}
func (c *FakeJobs) Get(name string) (result *extensions.Job, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("jobs", c.ns, name), &extensions.Job{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Job), err
}
func (c *FakeJobs) List(opts api.ListOptions) (result *extensions.JobList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("jobs", c.ns, opts), &extensions.JobList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &extensions.JobList{}
for _, item := range obj.(*extensions.JobList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested jobs.
func (c *FakeJobs) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("jobs", c.ns, opts))
}

View file

@ -1,113 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeReplicaSets implements ReplicaSetInterface
type FakeReplicaSets struct {
Fake *FakeExtensions
ns string
}
func (c *FakeReplicaSets) Create(replicaSet *extensions.ReplicaSet) (result *extensions.ReplicaSet, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("replicasets", c.ns, replicaSet), &extensions.ReplicaSet{})
if obj == nil {
return nil, err
}
return obj.(*extensions.ReplicaSet), err
}
func (c *FakeReplicaSets) Update(replicaSet *extensions.ReplicaSet) (result *extensions.ReplicaSet, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("replicasets", c.ns, replicaSet), &extensions.ReplicaSet{})
if obj == nil {
return nil, err
}
return obj.(*extensions.ReplicaSet), err
}
func (c *FakeReplicaSets) UpdateStatus(replicaSet *extensions.ReplicaSet) (*extensions.ReplicaSet, error) {
obj, err := c.Fake.
Invokes(core.NewUpdateSubresourceAction("replicasets", "status", c.ns, replicaSet), &extensions.ReplicaSet{})
if obj == nil {
return nil, err
}
return obj.(*extensions.ReplicaSet), err
}
func (c *FakeReplicaSets) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("replicasets", c.ns, name), &extensions.ReplicaSet{})
return err
}
func (c *FakeReplicaSets) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("replicasets", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &extensions.ReplicaSetList{})
return err
}
func (c *FakeReplicaSets) Get(name string) (result *extensions.ReplicaSet, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("replicasets", c.ns, name), &extensions.ReplicaSet{})
if obj == nil {
return nil, err
}
return obj.(*extensions.ReplicaSet), err
}
func (c *FakeReplicaSets) List(opts api.ListOptions) (result *extensions.ReplicaSetList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("replicasets", c.ns, opts), &extensions.ReplicaSetList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &extensions.ReplicaSetList{}
for _, item := range obj.(*extensions.ReplicaSetList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested replicaSets.
func (c *FakeReplicaSets) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("replicasets", c.ns, opts))
}

View file

@ -1,23 +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 fake
// FakeScales implements ScaleInterface
type FakeScales struct {
Fake *FakeExtensions
ns string
}

View file

@ -1,46 +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 fake
import (
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/testing/core"
)
func (c *FakeScales) Get(kind string, name string) (result *extensions.Scale, err error) {
action := core.GetActionImpl{}
action.Verb = "get"
action.Namespace = c.ns
action.Resource = kind
action.Subresource = "scale"
action.Name = name
obj, err := c.Fake.Invokes(action, &extensions.Scale{})
result = obj.(*extensions.Scale)
return
}
func (c *FakeScales) Update(kind string, scale *extensions.Scale) (result *extensions.Scale, err error) {
action := core.UpdateActionImpl{}
action.Verb = "update"
action.Namespace = c.ns
action.Resource = kind
action.Subresource = "scale"
action.Object = scale
obj, err := c.Fake.Invokes(action, scale)
result = obj.(*extensions.Scale)
return
}

View file

@ -1,103 +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 fake
import (
api "k8s.io/kubernetes/pkg/api"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
core "k8s.io/kubernetes/pkg/client/testing/core"
labels "k8s.io/kubernetes/pkg/labels"
watch "k8s.io/kubernetes/pkg/watch"
)
// FakeThirdPartyResources implements ThirdPartyResourceInterface
type FakeThirdPartyResources struct {
Fake *FakeExtensions
ns string
}
func (c *FakeThirdPartyResources) Create(thirdPartyResource *extensions.ThirdPartyResource) (result *extensions.ThirdPartyResource, err error) {
obj, err := c.Fake.
Invokes(core.NewCreateAction("thirdpartyresources", c.ns, thirdPartyResource), &extensions.ThirdPartyResource{})
if obj == nil {
return nil, err
}
return obj.(*extensions.ThirdPartyResource), err
}
func (c *FakeThirdPartyResources) Update(thirdPartyResource *extensions.ThirdPartyResource) (result *extensions.ThirdPartyResource, err error) {
obj, err := c.Fake.
Invokes(core.NewUpdateAction("thirdpartyresources", c.ns, thirdPartyResource), &extensions.ThirdPartyResource{})
if obj == nil {
return nil, err
}
return obj.(*extensions.ThirdPartyResource), err
}
func (c *FakeThirdPartyResources) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.
Invokes(core.NewDeleteAction("thirdpartyresources", c.ns, name), &extensions.ThirdPartyResource{})
return err
}
func (c *FakeThirdPartyResources) DeleteCollection(options *api.DeleteOptions, listOptions api.ListOptions) error {
action := core.NewDeleteCollectionAction("thirdpartyresources", c.ns, listOptions)
_, err := c.Fake.Invokes(action, &extensions.ThirdPartyResourceList{})
return err
}
func (c *FakeThirdPartyResources) Get(name string) (result *extensions.ThirdPartyResource, err error) {
obj, err := c.Fake.
Invokes(core.NewGetAction("thirdpartyresources", c.ns, name), &extensions.ThirdPartyResource{})
if obj == nil {
return nil, err
}
return obj.(*extensions.ThirdPartyResource), err
}
func (c *FakeThirdPartyResources) List(opts api.ListOptions) (result *extensions.ThirdPartyResourceList, err error) {
obj, err := c.Fake.
Invokes(core.NewListAction("thirdpartyresources", c.ns, opts), &extensions.ThirdPartyResourceList{})
if obj == nil {
return nil, err
}
label := opts.LabelSelector
if label == nil {
label = labels.Everything()
}
list := &extensions.ThirdPartyResourceList{}
for _, item := range obj.(*extensions.ThirdPartyResourceList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested thirdPartyResources.
func (c *FakeThirdPartyResources) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(core.NewWatchAction("thirdpartyresources", c.ns, opts))
}

View file

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

View file

@ -1,69 +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 auth_test
import (
"io/ioutil"
"os"
"reflect"
"testing"
clientauth "k8s.io/kubernetes/pkg/client/unversioned/auth"
)
func TestLoadFromFile(t *testing.T) {
loadAuthInfoTests := []struct {
authData string
authInfo *clientauth.Info
expectErr bool
}{
{
`{"user": "user", "password": "pass"}`,
&clientauth.Info{User: "user", Password: "pass"},
false,
},
{
"", nil, true,
},
}
for _, loadAuthInfoTest := range loadAuthInfoTests {
tt := loadAuthInfoTest
aifile, err := ioutil.TempFile("", "testAuthInfo")
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if tt.authData != "missing" {
defer os.Remove(aifile.Name())
defer aifile.Close()
_, err = aifile.WriteString(tt.authData)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
} else {
aifile.Close()
os.Remove(aifile.Name())
}
authInfo, err := clientauth.LoadFromFile(aifile.Name())
gotErr := err != nil
if gotErr != tt.expectErr {
t.Errorf("expected errorness: %v, actual errorness: %v", tt.expectErr, gotErr)
}
if !reflect.DeepEqual(authInfo, tt.authInfo) {
t.Errorf("Expected %v, got %v", tt.authInfo, authInfo)
}
}
}

View file

@ -20,6 +20,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/client/restclient"
)
type AutoscalingInterface interface {
@ -28,26 +29,26 @@ type AutoscalingInterface interface {
// AutoscalingClient is used to interact with Kubernetes autoscaling features.
type AutoscalingClient struct {
*RESTClient
*restclient.RESTClient
}
func (c *AutoscalingClient) HorizontalPodAutoscalers(namespace string) HorizontalPodAutoscalerInterface {
return newHorizontalPodAutoscalersV1(c, namespace)
}
func NewAutoscaling(c *Config) (*AutoscalingClient, error) {
func NewAutoscaling(c *restclient.Config) (*AutoscalingClient, error) {
config := *c
if err := setAutoscalingDefaults(&config); err != nil {
return nil, err
}
client, err := RESTClientFor(&config)
client, err := restclient.RESTClientFor(&config)
if err != nil {
return nil, err
}
return &AutoscalingClient{client}, nil
}
func NewAutoscalingOrDie(c *Config) *AutoscalingClient {
func NewAutoscalingOrDie(c *restclient.Config) *AutoscalingClient {
client, err := NewAutoscaling(c)
if err != nil {
panic(err)
@ -55,7 +56,7 @@ func NewAutoscalingOrDie(c *Config) *AutoscalingClient {
return client
}
func setAutoscalingDefaults(config *Config) error {
func setAutoscalingDefaults(config *restclient.Config) error {
// if autoscaling group is not registered, return an error
g, err := registered.Group(autoscaling.GroupName)
if err != nil {
@ -63,7 +64,7 @@ func setAutoscalingDefaults(config *Config) error {
}
config.APIPath = defaultAPIPath
if config.UserAgent == "" {
config.UserAgent = DefaultKubernetesUserAgent()
config.UserAgent = restclient.DefaultKubernetesUserAgent()
}
// TODO: Unconditionally set the config.Version, until we fix the config.
//if config.Version == "" {

View file

@ -0,0 +1,83 @@
/*
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 (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/client/restclient"
)
type BatchInterface interface {
JobsNamespacer
}
// BatchClient is used to interact with Kubernetes batch features.
type BatchClient struct {
*restclient.RESTClient
}
func (c *BatchClient) Jobs(namespace string) JobInterface {
return newJobsV1(c, namespace)
}
func NewBatch(c *restclient.Config) (*BatchClient, error) {
config := *c
if err := setBatchDefaults(&config); err != nil {
return nil, err
}
client, err := restclient.RESTClientFor(&config)
if err != nil {
return nil, err
}
return &BatchClient{client}, nil
}
func NewBatchOrDie(c *restclient.Config) *BatchClient {
client, err := NewBatch(c)
if err != nil {
panic(err)
}
return client
}
func setBatchDefaults(config *restclient.Config) error {
// if batch group is not registered, return an error
g, err := registered.Group(batch.GroupName)
if err != nil {
return err
}
config.APIPath = defaultAPIPath
if config.UserAgent == "" {
config.UserAgent = restclient.DefaultKubernetesUserAgent()
}
// TODO: Unconditionally set the config.Version, until we fix the config.
//if config.Version == "" {
copyGroupVersion := g.GroupVersion
config.GroupVersion = &copyGroupVersion
//}
config.Codec = api.Codecs.LegacyCodec(*config.GroupVersion)
if config.QPS == 0 {
config.QPS = 5
}
if config.Burst == 0 {
config.Burst = 10
}
return nil
}

View file

@ -20,6 +20,9 @@ import (
"net"
"net/url"
"strings"
"k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/client/typed/discovery"
)
// Interface holds the methods for clients of Kubernetes,
@ -42,8 +45,9 @@ type Interface interface {
ComponentStatusesInterface
ConfigMapsNamespacer
Autoscaling() AutoscalingInterface
Batch() BatchInterface
Extensions() ExtensionsInterface
Discovery() DiscoveryInterface
Discovery() discovery.DiscoveryInterface
}
func (c *Client) ReplicationControllers(namespace string) ReplicationControllerInterface {
@ -111,19 +115,11 @@ func (c *Client) ConfigMaps(namespace string) ConfigMapsInterface {
// Client is the implementation of a Kubernetes client.
type Client struct {
*RESTClient
*restclient.RESTClient
*AutoscalingClient
*BatchClient
*ExtensionsClient
*DiscoveryClient
}
func stringDoesntExistIn(str string, slice []string) bool {
for _, s := range slice {
if s == str {
return false
}
}
return true
*discovery.DiscoveryClient
}
// IsTimeout tests if this is a timeout error in the underlying transport.
@ -152,10 +148,14 @@ func (c *Client) Autoscaling() AutoscalingInterface {
return c.AutoscalingClient
}
func (c *Client) Batch() BatchInterface {
return c.BatchClient
}
func (c *Client) Extensions() ExtensionsInterface {
return c.ExtensionsClient
}
func (c *Client) Discovery() DiscoveryInterface {
func (c *Client) Discovery() discovery.DiscoveryInterface {
return c.DiscoveryClient
}

View file

@ -1,308 +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"
"net/http"
"net/http/httptest"
"reflect"
"testing"
"github.com/emicklei/go-restful/swagger"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/version"
)
func TestGetServerVersion(t *testing.T) {
expect := version.Info{
Major: "foo",
Minor: "bar",
GitCommit: "baz",
}
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
output, err := json.Marshal(expect)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}))
// TODO: Uncomment when fix #19254
// defer server.Close()
client := NewOrDie(&Config{Host: server.URL})
got, err := client.Discovery().ServerVersion()
if err != nil {
t.Fatalf("unexpected encoding error: %v", err)
}
if e, a := expect, *got; !reflect.DeepEqual(e, a) {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestGetServerGroupsWithV1Server(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var obj interface{}
switch req.URL.Path {
case "/api":
obj = &unversioned.APIVersions{
Versions: []string{
"v1",
},
}
default:
w.WriteHeader(http.StatusNotFound)
return
}
output, err := json.Marshal(obj)
if err != nil {
t.Fatalf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}))
// TODO: Uncomment when fix #19254
// defer server.Close()
client := NewOrDie(&Config{Host: server.URL})
// ServerGroups should not return an error even if server returns error at /api and /apis
apiGroupList, err := client.Discovery().ServerGroups()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
groupVersions := ExtractGroupVersions(apiGroupList)
if !reflect.DeepEqual(groupVersions, []string{"v1"}) {
t.Errorf("expected: %q, got: %q", []string{"v1"}, groupVersions)
}
}
func TestGetServerResourcesWithV1Server(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var obj interface{}
switch req.URL.Path {
case "/api":
obj = &unversioned.APIVersions{
Versions: []string{
"v1",
},
}
default:
w.WriteHeader(http.StatusNotFound)
return
}
output, err := json.Marshal(obj)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}))
// TODO: Uncomment when fix #19254
// defer server.Close()
client := NewOrDie(&Config{Host: server.URL})
// ServerResources should not return an error even if server returns error at /api/v1.
resourceMap, err := client.Discovery().ServerResources()
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if _, found := resourceMap["v1"]; !found {
t.Errorf("missing v1 in resource map")
}
}
func TestGetServerResources(t *testing.T) {
stable := unversioned.APIResourceList{
GroupVersion: "v1",
APIResources: []unversioned.APIResource{
{"pods", true, "Pod"},
{"services", true, "Service"},
{"namespaces", false, "Namespace"},
},
}
beta := unversioned.APIResourceList{
GroupVersion: "extensions/v1",
APIResources: []unversioned.APIResource{
{"deployments", true, "Deployment"},
{"ingresses", true, "Ingress"},
{"jobs", true, "Job"},
},
}
tests := []struct {
resourcesList *unversioned.APIResourceList
path string
request string
expectErr bool
}{
{
resourcesList: &stable,
path: "/api/v1",
request: "v1",
expectErr: false,
},
{
resourcesList: &beta,
path: "/apis/extensions/v1beta1",
request: "extensions/v1beta1",
expectErr: false,
},
{
resourcesList: &stable,
path: "/api/v1",
request: "foobar",
expectErr: true,
},
}
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var list interface{}
switch req.URL.Path {
case "/api/v1":
list = &stable
case "/apis/extensions/v1beta1":
list = &beta
case "/api":
list = &unversioned.APIVersions{
Versions: []string{
"v1",
},
}
case "/apis":
list = &unversioned.APIGroupList{
Groups: []unversioned.APIGroup{
{
Versions: []unversioned.GroupVersionForDiscovery{
{GroupVersion: "extensions/v1beta1"},
},
},
},
}
default:
t.Logf("unexpected request: %s", req.URL.Path)
w.WriteHeader(http.StatusNotFound)
return
}
output, err := json.Marshal(list)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}))
// TODO: Uncomment when fix #19254
// defer server.Close()
client := NewOrDie(&Config{Host: server.URL})
for _, test := range tests {
got, err := client.Discovery().ServerResourcesForGroupVersion(test.request)
if test.expectErr {
if err == nil {
t.Error("unexpected non-error")
}
continue
}
if err != nil {
t.Errorf("unexpected error: %v", err)
continue
}
if !reflect.DeepEqual(got, test.resourcesList) {
t.Errorf("expected:\n%v\ngot:\n%v\n", test.resourcesList, got)
}
}
resourceMap, err := client.Discovery().ServerResources()
if err != nil {
t.Errorf("unexpected error: %v", err)
}
for _, api := range []string{"v1", "extensions/v1beta1"} {
if _, found := resourceMap[api]; !found {
t.Errorf("missing expected api: %s", api)
}
}
}
func swaggerSchemaFakeServer() (*httptest.Server, error) {
request := 1
var sErr error
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var resp interface{}
if request == 1 {
resp = unversioned.APIVersions{Versions: []string{"v1", "v2", "v3"}}
request++
} else {
resp = swagger.ApiDeclaration{}
}
output, err := json.Marshal(resp)
if err != nil {
sErr = err
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}))
return server, sErr
}
func TestGetSwaggerSchema(t *testing.T) {
expect := swagger.ApiDeclaration{}
server, err := swaggerSchemaFakeServer()
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
}
// TODO: Uncomment when fix #19254
// defer server.Close()
client := NewOrDie(&Config{Host: server.URL})
got, err := client.Discovery().SwaggerSchema(v1.SchemeGroupVersion)
if err != nil {
t.Fatalf("unexpected encoding error: %v", err)
}
if e, a := expect, *got; !reflect.DeepEqual(e, a) {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestGetSwaggerSchemaFail(t *testing.T) {
expErr := "API version: api.group/v4 is not supported by the server. Use one of: [v1 v2 v3]"
server, err := swaggerSchemaFakeServer()
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
}
// TODO: Uncomment when fix #19254
// defer server.Close()
client := NewOrDie(&Config{Host: server.URL})
got, err := client.Discovery().SwaggerSchema(unversioned.GroupVersion{Group: "api.group", Version: "v4"})
if got != nil {
t.Fatalf("unexpected response: %v", got)
}
if err.Error() != expErr {
t.Errorf("expected an error, got %v", err)
}
}

View file

@ -1,301 +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 (
"fmt"
"io/ioutil"
"os"
"reflect"
"testing"
"github.com/ghodss/yaml"
)
func newMergedConfig(certFile, certContent, keyFile, keyContent, caFile, caContent string, t *testing.T) Config {
if err := ioutil.WriteFile(certFile, []byte(certContent), 0644); err != nil {
t.Errorf("unexpected error: %v", err)
}
if err := ioutil.WriteFile(keyFile, []byte(keyContent), 0600); err != nil {
t.Errorf("unexpected error: %v", err)
}
if err := ioutil.WriteFile(caFile, []byte(caContent), 0644); err != nil {
t.Errorf("unexpected error: %v", err)
}
return Config{
AuthInfos: map[string]*AuthInfo{
"red-user": {Token: "red-token", ClientCertificateData: []byte(certContent), ClientKeyData: []byte(keyContent)},
"blue-user": {Token: "blue-token", ClientCertificate: certFile, ClientKey: keyFile}},
Clusters: map[string]*Cluster{
"cow-cluster": {Server: "http://cow.org:8080", CertificateAuthorityData: []byte(caContent)},
"chicken-cluster": {Server: "http://chicken.org:8080", CertificateAuthority: caFile}},
Contexts: map[string]*Context{
"federal-context": {AuthInfo: "red-user", Cluster: "cow-cluster"},
"shaker-context": {AuthInfo: "blue-user", Cluster: "chicken-cluster"}},
CurrentContext: "federal-context",
}
}
func TestMinifySuccess(t *testing.T) {
certFile, _ := ioutil.TempFile("", "")
defer os.Remove(certFile.Name())
keyFile, _ := ioutil.TempFile("", "")
defer os.Remove(keyFile.Name())
caFile, _ := ioutil.TempFile("", "")
defer os.Remove(caFile.Name())
mutatingConfig := newMergedConfig(certFile.Name(), "cert", keyFile.Name(), "key", caFile.Name(), "ca", t)
if err := MinifyConfig(&mutatingConfig); err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(mutatingConfig.Contexts) > 1 {
t.Errorf("unexpected contexts: %v", mutatingConfig.Contexts)
}
if _, exists := mutatingConfig.Contexts["federal-context"]; !exists {
t.Errorf("missing context")
}
if len(mutatingConfig.Clusters) > 1 {
t.Errorf("unexpected clusters: %v", mutatingConfig.Clusters)
}
if _, exists := mutatingConfig.Clusters["cow-cluster"]; !exists {
t.Errorf("missing cluster")
}
if len(mutatingConfig.AuthInfos) > 1 {
t.Errorf("unexpected users: %v", mutatingConfig.AuthInfos)
}
if _, exists := mutatingConfig.AuthInfos["red-user"]; !exists {
t.Errorf("missing user")
}
}
func TestMinifyMissingContext(t *testing.T) {
certFile, _ := ioutil.TempFile("", "")
defer os.Remove(certFile.Name())
keyFile, _ := ioutil.TempFile("", "")
defer os.Remove(keyFile.Name())
caFile, _ := ioutil.TempFile("", "")
defer os.Remove(caFile.Name())
mutatingConfig := newMergedConfig(certFile.Name(), "cert", keyFile.Name(), "key", caFile.Name(), "ca", t)
mutatingConfig.CurrentContext = "missing"
errMsg := "cannot locate context missing"
if err := MinifyConfig(&mutatingConfig); err == nil || err.Error() != errMsg {
t.Errorf("expected %v, got %v", errMsg, err)
}
}
func TestMinifyMissingCluster(t *testing.T) {
certFile, _ := ioutil.TempFile("", "")
defer os.Remove(certFile.Name())
keyFile, _ := ioutil.TempFile("", "")
defer os.Remove(keyFile.Name())
caFile, _ := ioutil.TempFile("", "")
defer os.Remove(caFile.Name())
mutatingConfig := newMergedConfig(certFile.Name(), "cert", keyFile.Name(), "key", caFile.Name(), "ca", t)
delete(mutatingConfig.Clusters, mutatingConfig.Contexts[mutatingConfig.CurrentContext].Cluster)
errMsg := "cannot locate cluster cow-cluster"
if err := MinifyConfig(&mutatingConfig); err == nil || err.Error() != errMsg {
t.Errorf("expected %v, got %v", errMsg, err)
}
}
func TestMinifyMissingAuthInfo(t *testing.T) {
certFile, _ := ioutil.TempFile("", "")
defer os.Remove(certFile.Name())
keyFile, _ := ioutil.TempFile("", "")
defer os.Remove(keyFile.Name())
caFile, _ := ioutil.TempFile("", "")
defer os.Remove(caFile.Name())
mutatingConfig := newMergedConfig(certFile.Name(), "cert", keyFile.Name(), "key", caFile.Name(), "ca", t)
delete(mutatingConfig.AuthInfos, mutatingConfig.Contexts[mutatingConfig.CurrentContext].AuthInfo)
errMsg := "cannot locate user red-user"
if err := MinifyConfig(&mutatingConfig); err == nil || err.Error() != errMsg {
t.Errorf("expected %v, got %v", errMsg, err)
}
}
func TestFlattenSuccess(t *testing.T) {
certFile, _ := ioutil.TempFile("", "")
defer os.Remove(certFile.Name())
keyFile, _ := ioutil.TempFile("", "")
defer os.Remove(keyFile.Name())
caFile, _ := ioutil.TempFile("", "")
defer os.Remove(caFile.Name())
certData := "cert"
keyData := "key"
caData := "ca"
unchangingCluster := "cow-cluster"
unchangingAuthInfo := "red-user"
changingCluster := "chicken-cluster"
changingAuthInfo := "blue-user"
startingConfig := newMergedConfig(certFile.Name(), certData, keyFile.Name(), keyData, caFile.Name(), caData, t)
mutatingConfig := startingConfig
if err := FlattenConfig(&mutatingConfig); err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(mutatingConfig.Contexts) != 2 {
t.Errorf("unexpected contexts: %v", mutatingConfig.Contexts)
}
if !reflect.DeepEqual(startingConfig.Contexts, mutatingConfig.Contexts) {
t.Errorf("expected %v, got %v", startingConfig.Contexts, mutatingConfig.Contexts)
}
if len(mutatingConfig.Clusters) != 2 {
t.Errorf("unexpected clusters: %v", mutatingConfig.Clusters)
}
if !reflect.DeepEqual(startingConfig.Clusters[unchangingCluster], mutatingConfig.Clusters[unchangingCluster]) {
t.Errorf("expected %v, got %v", startingConfig.Clusters[unchangingCluster], mutatingConfig.Clusters[unchangingCluster])
}
if len(mutatingConfig.Clusters[changingCluster].CertificateAuthority) != 0 {
t.Errorf("unexpected caFile")
}
if string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData) != caData {
t.Errorf("expected %v, got %v", caData, string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData))
}
if len(mutatingConfig.AuthInfos) != 2 {
t.Errorf("unexpected users: %v", mutatingConfig.AuthInfos)
}
if !reflect.DeepEqual(startingConfig.AuthInfos[unchangingAuthInfo], mutatingConfig.AuthInfos[unchangingAuthInfo]) {
t.Errorf("expected %v, got %v", startingConfig.AuthInfos[unchangingAuthInfo], mutatingConfig.AuthInfos[unchangingAuthInfo])
}
if len(mutatingConfig.AuthInfos[changingAuthInfo].ClientCertificate) != 0 {
t.Errorf("unexpected caFile")
}
if string(mutatingConfig.AuthInfos[changingAuthInfo].ClientCertificateData) != certData {
t.Errorf("expected %v, got %v", certData, string(mutatingConfig.AuthInfos[changingAuthInfo].ClientCertificateData))
}
if len(mutatingConfig.AuthInfos[changingAuthInfo].ClientKey) != 0 {
t.Errorf("unexpected caFile")
}
if string(mutatingConfig.AuthInfos[changingAuthInfo].ClientKeyData) != keyData {
t.Errorf("expected %v, got %v", keyData, string(mutatingConfig.AuthInfos[changingAuthInfo].ClientKeyData))
}
}
func ExampleMinifyAndShorten() {
certFile, _ := ioutil.TempFile("", "")
defer os.Remove(certFile.Name())
keyFile, _ := ioutil.TempFile("", "")
defer os.Remove(keyFile.Name())
caFile, _ := ioutil.TempFile("", "")
defer os.Remove(caFile.Name())
certData := "cert"
keyData := "key"
caData := "ca"
config := newMergedConfig(certFile.Name(), certData, keyFile.Name(), keyData, caFile.Name(), caData, nil)
MinifyConfig(&config)
ShortenConfig(&config)
output, _ := yaml.Marshal(config)
fmt.Printf("%s", string(output))
// Output:
// clusters:
// cow-cluster:
// LocationOfOrigin: ""
// certificate-authority-data: REDACTED
// server: http://cow.org:8080
// contexts:
// federal-context:
// LocationOfOrigin: ""
// cluster: cow-cluster
// user: red-user
// current-context: federal-context
// preferences: {}
// users:
// red-user:
// LocationOfOrigin: ""
// client-certificate-data: REDACTED
// client-key-data: REDACTED
// token: red-token
}
func TestShortenSuccess(t *testing.T) {
certFile, _ := ioutil.TempFile("", "")
defer os.Remove(certFile.Name())
keyFile, _ := ioutil.TempFile("", "")
defer os.Remove(keyFile.Name())
caFile, _ := ioutil.TempFile("", "")
defer os.Remove(caFile.Name())
certData := "cert"
keyData := "key"
caData := "ca"
unchangingCluster := "chicken-cluster"
unchangingAuthInfo := "blue-user"
changingCluster := "cow-cluster"
changingAuthInfo := "red-user"
startingConfig := newMergedConfig(certFile.Name(), certData, keyFile.Name(), keyData, caFile.Name(), caData, t)
mutatingConfig := startingConfig
ShortenConfig(&mutatingConfig)
if len(mutatingConfig.Contexts) != 2 {
t.Errorf("unexpected contexts: %v", mutatingConfig.Contexts)
}
if !reflect.DeepEqual(startingConfig.Contexts, mutatingConfig.Contexts) {
t.Errorf("expected %v, got %v", startingConfig.Contexts, mutatingConfig.Contexts)
}
redacted := string(redactedBytes)
if len(mutatingConfig.Clusters) != 2 {
t.Errorf("unexpected clusters: %v", mutatingConfig.Clusters)
}
if !reflect.DeepEqual(startingConfig.Clusters[unchangingCluster], mutatingConfig.Clusters[unchangingCluster]) {
t.Errorf("expected %v, got %v", startingConfig.Clusters[unchangingCluster], mutatingConfig.Clusters[unchangingCluster])
}
if string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData) != redacted {
t.Errorf("expected %v, got %v", redacted, string(mutatingConfig.Clusters[changingCluster].CertificateAuthorityData))
}
if len(mutatingConfig.AuthInfos) != 2 {
t.Errorf("unexpected users: %v", mutatingConfig.AuthInfos)
}
if !reflect.DeepEqual(startingConfig.AuthInfos[unchangingAuthInfo], mutatingConfig.AuthInfos[unchangingAuthInfo]) {
t.Errorf("expected %v, got %v", startingConfig.AuthInfos[unchangingAuthInfo], mutatingConfig.AuthInfos[unchangingAuthInfo])
}
if string(mutatingConfig.AuthInfos[changingAuthInfo].ClientCertificateData) != redacted {
t.Errorf("expected %v, got %v", redacted, string(mutatingConfig.AuthInfos[changingAuthInfo].ClientCertificateData))
}
if string(mutatingConfig.AuthInfos[changingAuthInfo].ClientKeyData) != redacted {
t.Errorf("expected %v, got %v", redacted, string(mutatingConfig.AuthInfos[changingAuthInfo].ClientKeyData))
}
}

View file

@ -29,7 +29,11 @@ type Config struct {
// Legacy field from pkg/api/types.go TypeMeta.
// TODO(jlowdermilk): remove this after eliminating downstream dependencies.
Kind string `json:"kind,omitempty"`
// Version of the schema for this config object.
// DEPRECATED: APIVersion is the preferred api version for communicating with the kubernetes cluster (v1, v2, etc).
// Because a cluster can run multiple API groups and potentially multiple versions of each, it no longer makes sense to specify
// a single value for the cluster version.
// This field isnt really needed anyway, so we are deprecating it without replacement.
// It will be ignored if it is present.
APIVersion string `json:"apiVersion,omitempty"`
// Preferences holds general information to be use for cli interactions
Preferences Preferences `json:"preferences"`

View file

@ -1,123 +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 (
"fmt"
"github.com/ghodss/yaml"
)
func ExampleEmptyConfig() {
defaultConfig := NewConfig()
output, err := yaml.Marshal(defaultConfig)
if err != nil {
fmt.Printf("Unexpected error: %v", err)
}
fmt.Printf("%v", string(output))
// Output:
// clusters: {}
// contexts: {}
// current-context: ""
// preferences: {}
// users: {}
}
func ExampleOfOptionsConfig() {
defaultConfig := NewConfig()
defaultConfig.Preferences.Colors = true
defaultConfig.Clusters["alfa"] = &Cluster{
Server: "https://alfa.org:8080",
APIVersion: "v1",
InsecureSkipTLSVerify: true,
CertificateAuthority: "path/to/my/cert-ca-filename",
}
defaultConfig.Clusters["bravo"] = &Cluster{
Server: "https://bravo.org:8080",
APIVersion: "v1",
InsecureSkipTLSVerify: false,
}
defaultConfig.AuthInfos["white-mage-via-cert"] = &AuthInfo{
ClientCertificate: "path/to/my/client-cert-filename",
ClientKey: "path/to/my/client-key-filename",
}
defaultConfig.AuthInfos["red-mage-via-token"] = &AuthInfo{
Token: "my-secret-token",
}
defaultConfig.Contexts["bravo-as-black-mage"] = &Context{
Cluster: "bravo",
AuthInfo: "black-mage-via-file",
Namespace: "yankee",
}
defaultConfig.Contexts["alfa-as-black-mage"] = &Context{
Cluster: "alfa",
AuthInfo: "black-mage-via-file",
Namespace: "zulu",
}
defaultConfig.Contexts["alfa-as-white-mage"] = &Context{
Cluster: "alfa",
AuthInfo: "white-mage-via-cert",
}
defaultConfig.CurrentContext = "alfa-as-white-mage"
output, err := yaml.Marshal(defaultConfig)
if err != nil {
fmt.Printf("Unexpected error: %v", err)
}
fmt.Printf("%v", string(output))
// Output:
// clusters:
// alfa:
// LocationOfOrigin: ""
// api-version: v1
// certificate-authority: path/to/my/cert-ca-filename
// insecure-skip-tls-verify: true
// server: https://alfa.org:8080
// bravo:
// LocationOfOrigin: ""
// api-version: v1
// server: https://bravo.org:8080
// contexts:
// alfa-as-black-mage:
// LocationOfOrigin: ""
// cluster: alfa
// namespace: zulu
// user: black-mage-via-file
// alfa-as-white-mage:
// LocationOfOrigin: ""
// cluster: alfa
// user: white-mage-via-cert
// bravo-as-black-mage:
// LocationOfOrigin: ""
// cluster: bravo
// namespace: yankee
// user: black-mage-via-file
// current-context: alfa-as-white-mage
// preferences:
// colors: true
// users:
// red-mage-via-token:
// LocationOfOrigin: ""
// token: my-secret-token
// white-mage-via-cert:
// LocationOfOrigin: ""
// client-certificate: path/to/my/client-cert-filename
// client-key: path/to/my/client-key-filename
}

View file

@ -28,7 +28,11 @@ type Config struct {
// Legacy field from pkg/api/types.go TypeMeta.
// TODO(jlowdermilk): remove this after eliminating downstream dependencies.
Kind string `json:"kind,omitempty"`
// Version of the schema for this config object.
// DEPRECATED: APIVersion is the preferred api version for communicating with the kubernetes cluster (v1, v2, etc).
// Because a cluster can run multiple API groups and potentially multiple versions of each, it no longer makes sense to specify
// a single value for the cluster version.
// This field isnt really needed anyway, so we are deprecating it without replacement.
// It will be ignored if it is present.
APIVersion string `json:"apiVersion,omitempty"`
// Preferences holds general information to be use for cli interactions
Preferences Preferences `json:"preferences"`

View file

@ -28,8 +28,7 @@ import (
"github.com/imdario/mergo"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/restclient"
clientauth "k8s.io/kubernetes/pkg/client/unversioned/auth"
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
)
@ -50,7 +49,7 @@ type ClientConfig interface {
// RawConfig returns the merged result of all overrides
RawConfig() (clientcmdapi.Config, error)
// ClientConfig returns a complete client config
ClientConfig() (*client.Config, error)
ClientConfig() (*restclient.Config, error)
// Namespace returns the namespace resulting from the merged
// result of all overrides and a boolean indicating if it was
// overridden
@ -85,7 +84,7 @@ func (config *DirectClientConfig) RawConfig() (clientcmdapi.Config, error) {
}
// ClientConfig implements ClientConfig
func (config *DirectClientConfig) ClientConfig() (*client.Config, error) {
func (config *DirectClientConfig) ClientConfig() (*restclient.Config, error) {
if err := config.ConfirmUsable(); err != nil {
return nil, err
}
@ -93,26 +92,21 @@ func (config *DirectClientConfig) ClientConfig() (*client.Config, error) {
configAuthInfo := config.getAuthInfo()
configClusterInfo := config.getCluster()
clientConfig := &client.Config{}
clientConfig := &restclient.Config{}
clientConfig.Host = configClusterInfo.Server
if u, err := url.ParseRequestURI(clientConfig.Host); err == nil && u.Opaque == "" && len(u.Path) > 1 {
u.RawQuery = ""
u.Fragment = ""
clientConfig.Host = u.String()
}
if len(configClusterInfo.APIVersion) != 0 {
gv, err := unversioned.ParseGroupVersion(configClusterInfo.APIVersion)
if err != nil {
return nil, err
}
clientConfig.GroupVersion = &gv
}
// only try to read the auth information if we are secure
if client.IsConfigTransportTLS(*clientConfig) {
if restclient.IsConfigTransportTLS(*clientConfig) {
var err error
// mergo is a first write wins for map value and a last writing wins for interface values
// NOTE: This behavior changed with https://github.com/imdario/mergo/commit/d304790b2ed594794496464fadd89d2bb266600a.
// Our mergo.Merge version is older than this change.
userAuthPartialConfig, err := getUserIdentificationPartialConfig(configAuthInfo, config.fallbackReader)
if err != nil {
return nil, err
@ -135,11 +129,11 @@ func (config *DirectClientConfig) ClientConfig() (*client.Config, error) {
// 1. configClusterInfo (the final result of command line flags and merged .kubeconfig files)
// 2. configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority)
// 3. load the ~/.kubernetes_auth file as a default
func getServerIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, configClusterInfo clientcmdapi.Cluster) (*client.Config, error) {
mergedConfig := &client.Config{}
func getServerIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, configClusterInfo clientcmdapi.Cluster) (*restclient.Config, error) {
mergedConfig := &restclient.Config{}
// configClusterInfo holds the information identify the server provided by .kubeconfig
configClientConfig := &client.Config{}
configClientConfig := &restclient.Config{}
configClientConfig.CAFile = configClusterInfo.CertificateAuthority
configClientConfig.CAData = configClusterInfo.CertificateAuthorityData
configClientConfig.Insecure = configClusterInfo.InsecureSkipTLSVerify
@ -155,8 +149,8 @@ func getServerIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo,
// 2. configAuthInfo.auth-path (this file can contain information that conflicts with #1, and we want #1 to win the priority)
// 3. if there is not enough information to idenfity the user, load try the ~/.kubernetes_auth file
// 4. if there is not enough information to identify the user, prompt if possible
func getUserIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, fallbackReader io.Reader) (*client.Config, error) {
mergedConfig := &client.Config{}
func getUserIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, fallbackReader io.Reader) (*restclient.Config, error) {
mergedConfig := &restclient.Config{}
// blindly overwrite existing values based on precedence
if len(configAuthInfo.Token) > 0 {
@ -180,7 +174,7 @@ func getUserIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, fa
promptedConfig := makeUserIdentificationConfig(*promptedAuthInfo)
previouslyMergedConfig := mergedConfig
mergedConfig = &client.Config{}
mergedConfig = &restclient.Config{}
mergo.Merge(mergedConfig, promptedConfig)
mergo.Merge(mergedConfig, previouslyMergedConfig)
}
@ -189,8 +183,8 @@ func getUserIdentificationPartialConfig(configAuthInfo clientcmdapi.AuthInfo, fa
}
// makeUserIdentificationFieldsConfig returns a client.Config capable of being merged using mergo for only user identification information
func makeUserIdentificationConfig(info clientauth.Info) *client.Config {
config := &client.Config{}
func makeUserIdentificationConfig(info clientauth.Info) *restclient.Config {
config := &restclient.Config{}
config.Username = info.User
config.Password = info.Password
config.CertFile = info.CertFile
@ -200,8 +194,8 @@ func makeUserIdentificationConfig(info clientauth.Info) *client.Config {
}
// makeUserIdentificationFieldsConfig returns a client.Config capable of being merged using mergo for only server identification information
func makeServerIdentificationConfig(info clientauth.Info) client.Config {
config := client.Config{}
func makeServerIdentificationConfig(info clientauth.Info) restclient.Config {
config := restclient.Config{}
config.CAFile = info.CAFile
if info.Insecure != nil {
config.Insecure = *info.Insecure
@ -209,7 +203,7 @@ func makeServerIdentificationConfig(info clientauth.Info) client.Config {
return config
}
func canIdentifyUser(config client.Config) bool {
func canIdentifyUser(config restclient.Config) bool {
return len(config.Username) > 0 ||
(len(config.CertFile) > 0 || len(config.CertData) > 0) ||
len(config.BearerToken) > 0
@ -322,8 +316,8 @@ func (inClusterClientConfig) RawConfig() (clientcmdapi.Config, error) {
return clientcmdapi.Config{}, fmt.Errorf("inCluster environment config doesn't support multiple clusters")
}
func (inClusterClientConfig) ClientConfig() (*client.Config, error) {
return client.InClusterConfig()
func (inClusterClientConfig) ClientConfig() (*restclient.Config, error) {
return restclient.InClusterConfig()
}
func (inClusterClientConfig) Namespace() (string, error) {
@ -356,10 +350,10 @@ func (inClusterClientConfig) Possible() bool {
// components. Warnings should reflect this usage. If neither masterUrl or kubeconfigPath
// are passed in we fallback to inClusterConfig. If inClusterConfig fails, we fallback
// to the default config.
func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*client.Config, error) {
func BuildConfigFromFlags(masterUrl, kubeconfigPath string) (*restclient.Config, error) {
if kubeconfigPath == "" && masterUrl == "" {
glog.Warningf("Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.")
kubeconfig, err := client.InClusterConfig()
kubeconfig, err := restclient.InClusterConfig()
if err == nil {
return kubeconfig, nil
}

View file

@ -1,252 +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 clientcmd
import (
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api/testapi"
client "k8s.io/kubernetes/pkg/client/unversioned"
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
)
func createValidTestConfig() *clientcmdapi.Config {
const (
server = "https://anything.com:8080"
token = "the-token"
)
config := clientcmdapi.NewConfig()
config.Clusters["clean"] = &clientcmdapi.Cluster{
Server: server,
APIVersion: testapi.Default.GroupVersion().String(),
}
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
Token: token,
}
config.Contexts["clean"] = &clientcmdapi.Context{
Cluster: "clean",
AuthInfo: "clean",
}
config.CurrentContext = "clean"
return config
}
func TestMergeContext(t *testing.T) {
const namespace = "overriden-namespace"
config := createValidTestConfig()
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{})
_, overridden, err := clientBuilder.Namespace()
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if overridden {
t.Error("Expected namespace to not be overridden")
}
clientBuilder = NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{
Context: clientcmdapi.Context{
Namespace: namespace,
},
})
actual, overridden, err := clientBuilder.Namespace()
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if !overridden {
t.Error("Expected namespace to be overridden")
}
matchStringArg(namespace, actual, t)
}
func TestCertificateData(t *testing.T) {
caData := []byte("ca-data")
certData := []byte("cert-data")
keyData := []byte("key-data")
config := clientcmdapi.NewConfig()
config.Clusters["clean"] = &clientcmdapi.Cluster{
Server: "https://localhost:8443",
APIVersion: testapi.Default.GroupVersion().String(),
CertificateAuthorityData: caData,
}
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
ClientCertificateData: certData,
ClientKeyData: keyData,
}
config.Contexts["clean"] = &clientcmdapi.Context{
Cluster: "clean",
AuthInfo: "clean",
}
config.CurrentContext = "clean"
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{})
clientConfig, err := clientBuilder.ClientConfig()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
// Make sure cert data gets into config (will override file paths)
matchByteArg(caData, clientConfig.TLSClientConfig.CAData, t)
matchByteArg(certData, clientConfig.TLSClientConfig.CertData, t)
matchByteArg(keyData, clientConfig.TLSClientConfig.KeyData, t)
}
func TestBasicAuthData(t *testing.T) {
username := "myuser"
password := "mypass"
config := clientcmdapi.NewConfig()
config.Clusters["clean"] = &clientcmdapi.Cluster{
Server: "https://localhost:8443",
APIVersion: testapi.Default.GroupVersion().String(),
}
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
Username: username,
Password: password,
}
config.Contexts["clean"] = &clientcmdapi.Context{
Cluster: "clean",
AuthInfo: "clean",
}
config.CurrentContext = "clean"
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{})
clientConfig, err := clientBuilder.ClientConfig()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
// Make sure basic auth data gets into config
matchStringArg(username, clientConfig.Username, t)
matchStringArg(password, clientConfig.Password, t)
}
func TestCreateClean(t *testing.T) {
config := createValidTestConfig()
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{})
clientConfig, err := clientBuilder.ClientConfig()
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
matchStringArg(config.Clusters["clean"].Server, clientConfig.Host, t)
matchStringArg("", clientConfig.APIPath, t)
matchStringArg(config.Clusters["clean"].APIVersion, clientConfig.GroupVersion.String(), t)
matchBoolArg(config.Clusters["clean"].InsecureSkipTLSVerify, clientConfig.Insecure, t)
matchStringArg(config.AuthInfos["clean"].Token, clientConfig.BearerToken, t)
}
func TestCreateCleanWithPrefix(t *testing.T) {
tt := []struct {
server string
host string
}{
{"https://anything.com:8080/foo/bar", "https://anything.com:8080/foo/bar"},
{"http://anything.com:8080/foo/bar", "http://anything.com:8080/foo/bar"},
{"http://anything.com:8080/foo/bar/", "http://anything.com:8080/foo/bar/"},
{"http://anything.com:8080/", "http://anything.com:8080/"},
{"http://anything.com:8080//", "http://anything.com:8080//"},
{"anything.com:8080/foo/bar", "anything.com:8080/foo/bar"},
{"anything.com:8080", "anything.com:8080"},
{"anything.com", "anything.com"},
{"anything", "anything"},
}
// WARNING: EnvVarCluster.Server is set during package loading time and can not be overriden by os.Setenv inside this test
EnvVarCluster.Server = ""
tt = append(tt, struct{ server, host string }{"", "http://localhost:8080"})
for _, tc := range tt {
config := createValidTestConfig()
cleanConfig := config.Clusters["clean"]
cleanConfig.Server = tc.server
config.Clusters["clean"] = cleanConfig
clientBuilder := NewNonInteractiveClientConfig(*config, "clean", &ConfigOverrides{})
clientConfig, err := clientBuilder.ClientConfig()
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
matchStringArg(tc.host, clientConfig.Host, t)
}
}
func TestCreateCleanDefault(t *testing.T) {
config := createValidTestConfig()
clientBuilder := NewDefaultClientConfig(*config, &ConfigOverrides{})
clientConfig, err := clientBuilder.ClientConfig()
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
matchStringArg(config.Clusters["clean"].Server, clientConfig.Host, t)
matchStringArg(config.Clusters["clean"].APIVersion, clientConfig.GroupVersion.String(), t)
matchBoolArg(config.Clusters["clean"].InsecureSkipTLSVerify, clientConfig.Insecure, t)
matchStringArg(config.AuthInfos["clean"].Token, clientConfig.BearerToken, t)
}
func TestCreateMissingContext(t *testing.T) {
const expectedErrorContains = "Context was not found for specified context"
config := createValidTestConfig()
clientBuilder := NewNonInteractiveClientConfig(*config, "not-present", &ConfigOverrides{})
clientConfig, err := clientBuilder.ClientConfig()
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
expectedConfig := &client.Config{Host: clientConfig.Host}
if !reflect.DeepEqual(expectedConfig, clientConfig) {
t.Errorf("Expected %#v, got %#v", expectedConfig, clientConfig)
}
}
func matchBoolArg(expected, got bool, t *testing.T) {
if expected != got {
t.Errorf("Expected %v, got %v", expected, got)
}
}
func matchStringArg(expected, got string, t *testing.T) {
if expected != got {
t.Errorf("Expected %q, got %q", expected, got)
}
}
func matchByteArg(expected, got []byte, t *testing.T) {
if !reflect.DeepEqual(expected, got) {
t.Errorf("Expected %v, got %v", expected, got)
}
}

View file

@ -1,562 +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 clientcmd
import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"reflect"
"strings"
"testing"
"github.com/ghodss/yaml"
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
clientcmdlatest "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api/latest"
"k8s.io/kubernetes/pkg/runtime"
)
var (
testConfigAlfa = clientcmdapi.Config{
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"red-user": {Token: "red-token"}},
Clusters: map[string]*clientcmdapi.Cluster{
"cow-cluster": {Server: "http://cow.org:8080"}},
Contexts: map[string]*clientcmdapi.Context{
"federal-context": {AuthInfo: "red-user", Cluster: "cow-cluster", Namespace: "hammer-ns"}},
}
testConfigBravo = clientcmdapi.Config{
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"black-user": {Token: "black-token"}},
Clusters: map[string]*clientcmdapi.Cluster{
"pig-cluster": {Server: "http://pig.org:8080"}},
Contexts: map[string]*clientcmdapi.Context{
"queen-anne-context": {AuthInfo: "black-user", Cluster: "pig-cluster", Namespace: "saw-ns"}},
}
testConfigCharlie = clientcmdapi.Config{
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"green-user": {Token: "green-token"}},
Clusters: map[string]*clientcmdapi.Cluster{
"horse-cluster": {Server: "http://horse.org:8080"}},
Contexts: map[string]*clientcmdapi.Context{
"shaker-context": {AuthInfo: "green-user", Cluster: "horse-cluster", Namespace: "chisel-ns"}},
}
testConfigDelta = clientcmdapi.Config{
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"blue-user": {Token: "blue-token"}},
Clusters: map[string]*clientcmdapi.Cluster{
"chicken-cluster": {Server: "http://chicken.org:8080"}},
Contexts: map[string]*clientcmdapi.Context{
"gothic-context": {AuthInfo: "blue-user", Cluster: "chicken-cluster", Namespace: "plane-ns"}},
}
testConfigConflictAlfa = clientcmdapi.Config{
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"red-user": {Token: "a-different-red-token"},
"yellow-user": {Token: "yellow-token"}},
Clusters: map[string]*clientcmdapi.Cluster{
"cow-cluster": {Server: "http://a-different-cow.org:8080", InsecureSkipTLSVerify: true},
"donkey-cluster": {Server: "http://donkey.org:8080", InsecureSkipTLSVerify: true}},
CurrentContext: "federal-context",
}
)
func TestNonExistentCommandLineFile(t *testing.T) {
loadingRules := ClientConfigLoadingRules{
ExplicitPath: "bogus_file",
}
_, err := loadingRules.Load()
if err == nil {
t.Fatalf("Expected error for missing command-line file, got none")
}
if !strings.Contains(err.Error(), "bogus_file") {
t.Fatalf("Expected error about 'bogus_file', got %s", err.Error())
}
}
func TestToleratingMissingFiles(t *testing.T) {
loadingRules := ClientConfigLoadingRules{
Precedence: []string{"bogus1", "bogus2", "bogus3"},
}
_, err := loadingRules.Load()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
}
func TestErrorReadingFile(t *testing.T) {
commandLineFile, _ := ioutil.TempFile("", "")
defer os.Remove(commandLineFile.Name())
if err := ioutil.WriteFile(commandLineFile.Name(), []byte("bogus value"), 0644); err != nil {
t.Fatalf("Error creating tempfile: %v", err)
}
loadingRules := ClientConfigLoadingRules{
ExplicitPath: commandLineFile.Name(),
}
_, err := loadingRules.Load()
if err == nil {
t.Fatalf("Expected error for unloadable file, got none")
}
if !strings.Contains(err.Error(), commandLineFile.Name()) {
t.Fatalf("Expected error about '%s', got %s", commandLineFile.Name(), err.Error())
}
}
func TestErrorReadingNonFile(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("Couldn't create tmpdir")
}
defer os.Remove(tmpdir)
loadingRules := ClientConfigLoadingRules{
ExplicitPath: tmpdir,
}
_, err = loadingRules.Load()
if err == nil {
t.Fatalf("Expected error for non-file, got none")
}
if !strings.Contains(err.Error(), tmpdir) {
t.Fatalf("Expected error about '%s', got %s", tmpdir, err.Error())
}
}
func TestConflictingCurrentContext(t *testing.T) {
commandLineFile, _ := ioutil.TempFile("", "")
defer os.Remove(commandLineFile.Name())
envVarFile, _ := ioutil.TempFile("", "")
defer os.Remove(envVarFile.Name())
mockCommandLineConfig := clientcmdapi.Config{
CurrentContext: "any-context-value",
}
mockEnvVarConfig := clientcmdapi.Config{
CurrentContext: "a-different-context",
}
WriteToFile(mockCommandLineConfig, commandLineFile.Name())
WriteToFile(mockEnvVarConfig, envVarFile.Name())
loadingRules := ClientConfigLoadingRules{
ExplicitPath: commandLineFile.Name(),
Precedence: []string{envVarFile.Name()},
}
mergedConfig, err := loadingRules.Load()
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if mergedConfig.CurrentContext != mockCommandLineConfig.CurrentContext {
t.Errorf("expected %v, got %v", mockCommandLineConfig.CurrentContext, mergedConfig.CurrentContext)
}
}
func TestLoadingEmptyMaps(t *testing.T) {
configFile, _ := ioutil.TempFile("", "")
defer os.Remove(configFile.Name())
mockConfig := clientcmdapi.Config{
CurrentContext: "any-context-value",
}
WriteToFile(mockConfig, configFile.Name())
config, err := LoadFromFile(configFile.Name())
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if config.Clusters == nil {
t.Error("expected config.Clusters to be non-nil")
}
if config.AuthInfos == nil {
t.Error("expected config.AuthInfos to be non-nil")
}
if config.Contexts == nil {
t.Error("expected config.Contexts to be non-nil")
}
}
func TestResolveRelativePaths(t *testing.T) {
pathResolutionConfig1 := clientcmdapi.Config{
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"relative-user-1": {ClientCertificate: "relative/client/cert", ClientKey: "../relative/client/key"},
"absolute-user-1": {ClientCertificate: "/absolute/client/cert", ClientKey: "/absolute/client/key"},
},
Clusters: map[string]*clientcmdapi.Cluster{
"relative-server-1": {CertificateAuthority: "../relative/ca"},
"absolute-server-1": {CertificateAuthority: "/absolute/ca"},
},
}
pathResolutionConfig2 := clientcmdapi.Config{
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"relative-user-2": {ClientCertificate: "relative/client/cert2", ClientKey: "../relative/client/key2"},
"absolute-user-2": {ClientCertificate: "/absolute/client/cert2", ClientKey: "/absolute/client/key2"},
},
Clusters: map[string]*clientcmdapi.Cluster{
"relative-server-2": {CertificateAuthority: "../relative/ca2"},
"absolute-server-2": {CertificateAuthority: "/absolute/ca2"},
},
}
configDir1, _ := ioutil.TempDir("", "")
configFile1 := path.Join(configDir1, ".kubeconfig")
configDir1, _ = filepath.Abs(configDir1)
defer os.Remove(configFile1)
configDir2, _ := ioutil.TempDir("", "")
configDir2, _ = ioutil.TempDir(configDir2, "")
configFile2 := path.Join(configDir2, ".kubeconfig")
configDir2, _ = filepath.Abs(configDir2)
defer os.Remove(configFile2)
WriteToFile(pathResolutionConfig1, configFile1)
WriteToFile(pathResolutionConfig2, configFile2)
loadingRules := ClientConfigLoadingRules{
Precedence: []string{configFile1, configFile2},
}
mergedConfig, err := loadingRules.Load()
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
foundClusterCount := 0
for key, cluster := range mergedConfig.Clusters {
if key == "relative-server-1" {
foundClusterCount++
matchStringArg(path.Join(configDir1, pathResolutionConfig1.Clusters["relative-server-1"].CertificateAuthority), cluster.CertificateAuthority, t)
}
if key == "relative-server-2" {
foundClusterCount++
matchStringArg(path.Join(configDir2, pathResolutionConfig2.Clusters["relative-server-2"].CertificateAuthority), cluster.CertificateAuthority, t)
}
if key == "absolute-server-1" {
foundClusterCount++
matchStringArg(pathResolutionConfig1.Clusters["absolute-server-1"].CertificateAuthority, cluster.CertificateAuthority, t)
}
if key == "absolute-server-2" {
foundClusterCount++
matchStringArg(pathResolutionConfig2.Clusters["absolute-server-2"].CertificateAuthority, cluster.CertificateAuthority, t)
}
}
if foundClusterCount != 4 {
t.Errorf("Expected 4 clusters, found %v: %v", foundClusterCount, mergedConfig.Clusters)
}
foundAuthInfoCount := 0
for key, authInfo := range mergedConfig.AuthInfos {
if key == "relative-user-1" {
foundAuthInfoCount++
matchStringArg(path.Join(configDir1, pathResolutionConfig1.AuthInfos["relative-user-1"].ClientCertificate), authInfo.ClientCertificate, t)
matchStringArg(path.Join(configDir1, pathResolutionConfig1.AuthInfos["relative-user-1"].ClientKey), authInfo.ClientKey, t)
}
if key == "relative-user-2" {
foundAuthInfoCount++
matchStringArg(path.Join(configDir2, pathResolutionConfig2.AuthInfos["relative-user-2"].ClientCertificate), authInfo.ClientCertificate, t)
matchStringArg(path.Join(configDir2, pathResolutionConfig2.AuthInfos["relative-user-2"].ClientKey), authInfo.ClientKey, t)
}
if key == "absolute-user-1" {
foundAuthInfoCount++
matchStringArg(pathResolutionConfig1.AuthInfos["absolute-user-1"].ClientCertificate, authInfo.ClientCertificate, t)
matchStringArg(pathResolutionConfig1.AuthInfos["absolute-user-1"].ClientKey, authInfo.ClientKey, t)
}
if key == "absolute-user-2" {
foundAuthInfoCount++
matchStringArg(pathResolutionConfig2.AuthInfos["absolute-user-2"].ClientCertificate, authInfo.ClientCertificate, t)
matchStringArg(pathResolutionConfig2.AuthInfos["absolute-user-2"].ClientKey, authInfo.ClientKey, t)
}
}
if foundAuthInfoCount != 4 {
t.Errorf("Expected 4 users, found %v: %v", foundAuthInfoCount, mergedConfig.AuthInfos)
}
}
func TestMigratingFile(t *testing.T) {
sourceFile, _ := ioutil.TempFile("", "")
defer os.Remove(sourceFile.Name())
destinationFile, _ := ioutil.TempFile("", "")
// delete the file so that we'll write to it
os.Remove(destinationFile.Name())
WriteToFile(testConfigAlfa, sourceFile.Name())
loadingRules := ClientConfigLoadingRules{
MigrationRules: map[string]string{destinationFile.Name(): sourceFile.Name()},
}
if _, err := loadingRules.Load(); err != nil {
t.Errorf("unexpected error %v", err)
}
// the load should have recreated this file
defer os.Remove(destinationFile.Name())
sourceContent, err := ioutil.ReadFile(sourceFile.Name())
if err != nil {
t.Errorf("unexpected error %v", err)
}
destinationContent, err := ioutil.ReadFile(destinationFile.Name())
if err != nil {
t.Errorf("unexpected error %v", err)
}
if !reflect.DeepEqual(sourceContent, destinationContent) {
t.Errorf("source and destination do not match")
}
}
func TestMigratingFileLeaveExistingFileAlone(t *testing.T) {
sourceFile, _ := ioutil.TempFile("", "")
defer os.Remove(sourceFile.Name())
destinationFile, _ := ioutil.TempFile("", "")
defer os.Remove(destinationFile.Name())
WriteToFile(testConfigAlfa, sourceFile.Name())
loadingRules := ClientConfigLoadingRules{
MigrationRules: map[string]string{destinationFile.Name(): sourceFile.Name()},
}
if _, err := loadingRules.Load(); err != nil {
t.Errorf("unexpected error %v", err)
}
destinationContent, err := ioutil.ReadFile(destinationFile.Name())
if err != nil {
t.Errorf("unexpected error %v", err)
}
if len(destinationContent) > 0 {
t.Errorf("destination should not have been touched")
}
}
func TestMigratingFileSourceMissingSkip(t *testing.T) {
sourceFilename := "some-missing-file"
destinationFile, _ := ioutil.TempFile("", "")
// delete the file so that we'll write to it
os.Remove(destinationFile.Name())
loadingRules := ClientConfigLoadingRules{
MigrationRules: map[string]string{destinationFile.Name(): sourceFilename},
}
if _, err := loadingRules.Load(); err != nil {
t.Errorf("unexpected error %v", err)
}
if _, err := os.Stat(destinationFile.Name()); !os.IsNotExist(err) {
t.Errorf("destination should not exist")
}
}
func ExampleNoMergingOnExplicitPaths() {
commandLineFile, _ := ioutil.TempFile("", "")
defer os.Remove(commandLineFile.Name())
envVarFile, _ := ioutil.TempFile("", "")
defer os.Remove(envVarFile.Name())
WriteToFile(testConfigAlfa, commandLineFile.Name())
WriteToFile(testConfigConflictAlfa, envVarFile.Name())
loadingRules := ClientConfigLoadingRules{
ExplicitPath: commandLineFile.Name(),
Precedence: []string{envVarFile.Name()},
}
mergedConfig, err := loadingRules.Load()
json, err := runtime.Encode(clientcmdlatest.Codec, mergedConfig)
if err != nil {
fmt.Printf("Unexpected error: %v", err)
}
output, err := yaml.JSONToYAML(json)
if err != nil {
fmt.Printf("Unexpected error: %v", err)
}
fmt.Printf("%v", string(output))
// Output:
// apiVersion: v1
// clusters:
// - cluster:
// server: http://cow.org:8080
// name: cow-cluster
// contexts:
// - context:
// cluster: cow-cluster
// namespace: hammer-ns
// user: red-user
// name: federal-context
// current-context: ""
// kind: Config
// preferences: {}
// users:
// - name: red-user
// user:
// token: red-token
}
func ExampleMergingSomeWithConflict() {
commandLineFile, _ := ioutil.TempFile("", "")
defer os.Remove(commandLineFile.Name())
envVarFile, _ := ioutil.TempFile("", "")
defer os.Remove(envVarFile.Name())
WriteToFile(testConfigAlfa, commandLineFile.Name())
WriteToFile(testConfigConflictAlfa, envVarFile.Name())
loadingRules := ClientConfigLoadingRules{
Precedence: []string{commandLineFile.Name(), envVarFile.Name()},
}
mergedConfig, err := loadingRules.Load()
json, err := runtime.Encode(clientcmdlatest.Codec, mergedConfig)
if err != nil {
fmt.Printf("Unexpected error: %v", err)
}
output, err := yaml.JSONToYAML(json)
if err != nil {
fmt.Printf("Unexpected error: %v", err)
}
fmt.Printf("%v", string(output))
// Output:
// apiVersion: v1
// clusters:
// - cluster:
// server: http://cow.org:8080
// name: cow-cluster
// - cluster:
// insecure-skip-tls-verify: true
// server: http://donkey.org:8080
// name: donkey-cluster
// contexts:
// - context:
// cluster: cow-cluster
// namespace: hammer-ns
// user: red-user
// name: federal-context
// current-context: federal-context
// kind: Config
// preferences: {}
// users:
// - name: red-user
// user:
// token: red-token
// - name: yellow-user
// user:
// token: yellow-token
}
func ExampleMergingEverythingNoConflicts() {
commandLineFile, _ := ioutil.TempFile("", "")
defer os.Remove(commandLineFile.Name())
envVarFile, _ := ioutil.TempFile("", "")
defer os.Remove(envVarFile.Name())
currentDirFile, _ := ioutil.TempFile("", "")
defer os.Remove(currentDirFile.Name())
homeDirFile, _ := ioutil.TempFile("", "")
defer os.Remove(homeDirFile.Name())
WriteToFile(testConfigAlfa, commandLineFile.Name())
WriteToFile(testConfigBravo, envVarFile.Name())
WriteToFile(testConfigCharlie, currentDirFile.Name())
WriteToFile(testConfigDelta, homeDirFile.Name())
loadingRules := ClientConfigLoadingRules{
Precedence: []string{commandLineFile.Name(), envVarFile.Name(), currentDirFile.Name(), homeDirFile.Name()},
}
mergedConfig, err := loadingRules.Load()
json, err := runtime.Encode(clientcmdlatest.Codec, mergedConfig)
if err != nil {
fmt.Printf("Unexpected error: %v", err)
}
output, err := yaml.JSONToYAML(json)
if err != nil {
fmt.Printf("Unexpected error: %v", err)
}
fmt.Printf("%v", string(output))
// Output:
// apiVersion: v1
// clusters:
// - cluster:
// server: http://chicken.org:8080
// name: chicken-cluster
// - cluster:
// server: http://cow.org:8080
// name: cow-cluster
// - cluster:
// server: http://horse.org:8080
// name: horse-cluster
// - cluster:
// server: http://pig.org:8080
// name: pig-cluster
// contexts:
// - context:
// cluster: cow-cluster
// namespace: hammer-ns
// user: red-user
// name: federal-context
// - context:
// cluster: chicken-cluster
// namespace: plane-ns
// user: blue-user
// name: gothic-context
// - context:
// cluster: pig-cluster
// namespace: saw-ns
// user: black-user
// name: queen-anne-context
// - context:
// cluster: horse-cluster
// namespace: chisel-ns
// user: green-user
// name: shaker-context
// current-context: ""
// kind: Config
// preferences: {}
// users:
// - name: black-user
// user:
// token: black-token
// - name: blue-user
// user:
// token: blue-token
// - name: green-user
// user:
// token: green-token
// - name: red-user
// user:
// token: red-token
}

View file

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

View file

@ -134,7 +134,7 @@ func RecommendedAuthOverrideFlags(prefix string) AuthOverrideFlags {
func RecommendedClusterOverrideFlags(prefix string) ClusterOverrideFlags {
return ClusterOverrideFlags{
APIServer: FlagInfo{prefix + FlagAPIServer, "", "", "The address and port of the Kubernetes API server"},
APIVersion: FlagInfo{prefix + FlagAPIVersion, "", "", "The API version to use when talking to the server"},
APIVersion: FlagInfo{prefix + FlagAPIVersion, "", "", "DEPRECATED: The API version to use when talking to the server"},
CertificateAuthority: FlagInfo{prefix + FlagCAFile, "", "", "Path to a cert. file for the certificate authority."},
InsecureSkipTLSVerify: FlagInfo{prefix + FlagInsecure, "", "false", "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure."},
}
@ -171,7 +171,9 @@ func BindAuthInfoFlags(authInfo *clientcmdapi.AuthInfo, flags *pflag.FlagSet, fl
// BindClusterFlags is a convenience method to bind the specified flags to their associated variables
func BindClusterFlags(clusterInfo *clientcmdapi.Cluster, flags *pflag.FlagSet, flagNames ClusterOverrideFlags) {
flagNames.APIServer.BindStringFlag(flags, &clusterInfo.Server)
// TODO: remove --api-version flag in 1.3.
flagNames.APIVersion.BindStringFlag(flags, &clusterInfo.APIVersion)
flags.MarkDeprecated(FlagAPIVersion, "flag is no longer respected and will be deleted in the next release")
flagNames.CertificateAuthority.BindStringFlag(flags, &clusterInfo.CertificateAuthority)
flagNames.InsecureSkipTLSVerify.BindBoolFlag(flags, &clusterInfo.InsecureSkipTLSVerify)
}

View file

@ -1,432 +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 clientcmd
import (
"io/ioutil"
"os"
"strings"
"testing"
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
)
func TestConfirmUsableBadInfoButOkConfig(t *testing.T) {
config := clientcmdapi.NewConfig()
config.Clusters["missing ca"] = &clientcmdapi.Cluster{
Server: "anything",
CertificateAuthority: "missing",
}
config.AuthInfos["error"] = &clientcmdapi.AuthInfo{
Username: "anything",
Token: "here",
}
config.Contexts["dirty"] = &clientcmdapi.Context{
Cluster: "missing ca",
AuthInfo: "error",
}
config.Clusters["clean"] = &clientcmdapi.Cluster{
Server: "anything",
}
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
Token: "here",
}
config.Contexts["clean"] = &clientcmdapi.Context{
Cluster: "clean",
AuthInfo: "clean",
}
badValidation := configValidationTest{
config: config,
expectedErrorSubstring: []string{"unable to read certificate-authority"},
}
okTest := configValidationTest{
config: config,
}
okTest.testConfirmUsable("clean", t)
badValidation.testConfig(t)
}
func TestConfirmUsableBadInfoConfig(t *testing.T) {
config := clientcmdapi.NewConfig()
config.Clusters["missing ca"] = &clientcmdapi.Cluster{
Server: "anything",
CertificateAuthority: "missing",
}
config.AuthInfos["error"] = &clientcmdapi.AuthInfo{
Username: "anything",
Token: "here",
}
config.Contexts["first"] = &clientcmdapi.Context{
Cluster: "missing ca",
AuthInfo: "error",
}
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"unable to read certificate-authority"},
}
test.testConfirmUsable("first", t)
}
func TestConfirmUsableEmptyConfig(t *testing.T) {
config := clientcmdapi.NewConfig()
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"invalid configuration: no configuration has been provided"},
}
test.testConfirmUsable("", t)
}
func TestConfirmUsableMissingConfig(t *testing.T) {
config := clientcmdapi.NewConfig()
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"invalid configuration: no configuration has been provided"},
}
test.testConfirmUsable("not-here", t)
}
func TestValidateEmptyConfig(t *testing.T) {
config := clientcmdapi.NewConfig()
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"invalid configuration: no configuration has been provided"},
}
test.testConfig(t)
}
func TestValidateMissingCurrentContextConfig(t *testing.T) {
config := clientcmdapi.NewConfig()
config.CurrentContext = "anything"
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"context was not found for specified "},
}
test.testConfig(t)
}
func TestIsContextNotFound(t *testing.T) {
config := clientcmdapi.NewConfig()
config.CurrentContext = "anything"
err := Validate(*config)
if !IsContextNotFound(err) {
t.Errorf("Expected context not found, but got %v", err)
}
if !IsConfigurationInvalid(err) {
t.Errorf("Expected configuration invalid, but got %v", err)
}
}
func TestIsEmptyConfig(t *testing.T) {
config := clientcmdapi.NewConfig()
err := Validate(*config)
if !IsEmptyConfig(err) {
t.Errorf("Expected context not found, but got %v", err)
}
if !IsConfigurationInvalid(err) {
t.Errorf("Expected configuration invalid, but got %v", err)
}
}
func TestIsConfigurationInvalid(t *testing.T) {
if newErrConfigurationInvalid([]error{}) != nil {
t.Errorf("unexpected error")
}
if newErrConfigurationInvalid([]error{ErrNoContext}) == ErrNoContext {
t.Errorf("unexpected error")
}
if newErrConfigurationInvalid([]error{ErrNoContext, ErrNoContext}) == nil {
t.Errorf("unexpected error")
}
if !IsConfigurationInvalid(newErrConfigurationInvalid([]error{ErrNoContext, ErrNoContext})) {
t.Errorf("unexpected error")
}
}
func TestValidateMissingReferencesConfig(t *testing.T) {
config := clientcmdapi.NewConfig()
config.CurrentContext = "anything"
config.Contexts["anything"] = &clientcmdapi.Context{Cluster: "missing", AuthInfo: "missing"}
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"user \"missing\" was not found for context \"anything\"", "cluster \"missing\" was not found for context \"anything\""},
}
test.testContext("anything", t)
test.testConfig(t)
}
func TestValidateEmptyContext(t *testing.T) {
config := clientcmdapi.NewConfig()
config.CurrentContext = "anything"
config.Contexts["anything"] = &clientcmdapi.Context{}
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"user was not specified for context \"anything\"", "cluster was not specified for context \"anything\""},
}
test.testContext("anything", t)
test.testConfig(t)
}
func TestValidateEmptyClusterInfo(t *testing.T) {
config := clientcmdapi.NewConfig()
config.Clusters["empty"] = &clientcmdapi.Cluster{}
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"cluster has no server defined"},
}
test.testCluster("empty", t)
test.testConfig(t)
}
func TestValidateMissingCAFileClusterInfo(t *testing.T) {
config := clientcmdapi.NewConfig()
config.Clusters["missing ca"] = &clientcmdapi.Cluster{
Server: "anything",
CertificateAuthority: "missing",
}
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"unable to read certificate-authority"},
}
test.testCluster("missing ca", t)
test.testConfig(t)
}
func TestValidateCleanClusterInfo(t *testing.T) {
config := clientcmdapi.NewConfig()
config.Clusters["clean"] = &clientcmdapi.Cluster{
Server: "anything",
}
test := configValidationTest{
config: config,
}
test.testCluster("clean", t)
test.testConfig(t)
}
func TestValidateCleanWithCAClusterInfo(t *testing.T) {
tempFile, _ := ioutil.TempFile("", "")
defer os.Remove(tempFile.Name())
config := clientcmdapi.NewConfig()
config.Clusters["clean"] = &clientcmdapi.Cluster{
Server: "anything",
CertificateAuthority: tempFile.Name(),
}
test := configValidationTest{
config: config,
}
test.testCluster("clean", t)
test.testConfig(t)
}
func TestValidateEmptyAuthInfo(t *testing.T) {
config := clientcmdapi.NewConfig()
config.AuthInfos["error"] = &clientcmdapi.AuthInfo{}
test := configValidationTest{
config: config,
}
test.testAuthInfo("error", t)
test.testConfig(t)
}
func TestValidateCertFilesNotFoundAuthInfo(t *testing.T) {
config := clientcmdapi.NewConfig()
config.AuthInfos["error"] = &clientcmdapi.AuthInfo{
ClientCertificate: "missing",
ClientKey: "missing",
}
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"unable to read client-cert", "unable to read client-key"},
}
test.testAuthInfo("error", t)
test.testConfig(t)
}
func TestValidateCertDataOverridesFiles(t *testing.T) {
tempFile, _ := ioutil.TempFile("", "")
defer os.Remove(tempFile.Name())
config := clientcmdapi.NewConfig()
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
ClientCertificate: tempFile.Name(),
ClientCertificateData: []byte("certdata"),
ClientKey: tempFile.Name(),
ClientKeyData: []byte("keydata"),
}
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"client-cert-data and client-cert are both specified", "client-key-data and client-key are both specified"},
}
test.testAuthInfo("clean", t)
test.testConfig(t)
}
func TestValidateCleanCertFilesAuthInfo(t *testing.T) {
tempFile, _ := ioutil.TempFile("", "")
defer os.Remove(tempFile.Name())
config := clientcmdapi.NewConfig()
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
ClientCertificate: tempFile.Name(),
ClientKey: tempFile.Name(),
}
test := configValidationTest{
config: config,
}
test.testAuthInfo("clean", t)
test.testConfig(t)
}
func TestValidateCleanTokenAuthInfo(t *testing.T) {
config := clientcmdapi.NewConfig()
config.AuthInfos["clean"] = &clientcmdapi.AuthInfo{
Token: "any-value",
}
test := configValidationTest{
config: config,
}
test.testAuthInfo("clean", t)
test.testConfig(t)
}
func TestValidateMultipleMethodsAuthInfo(t *testing.T) {
config := clientcmdapi.NewConfig()
config.AuthInfos["error"] = &clientcmdapi.AuthInfo{
Token: "token",
Username: "username",
}
test := configValidationTest{
config: config,
expectedErrorSubstring: []string{"more than one authentication method", "token", "basicAuth"},
}
test.testAuthInfo("error", t)
test.testConfig(t)
}
type configValidationTest struct {
config *clientcmdapi.Config
expectedErrorSubstring []string
}
func (c configValidationTest) testContext(contextName string, t *testing.T) {
errs := validateContext(contextName, *c.config.Contexts[contextName], *c.config)
if len(c.expectedErrorSubstring) != 0 {
if len(errs) == 0 {
t.Errorf("Expected error containing: %v", c.expectedErrorSubstring)
}
for _, curr := range c.expectedErrorSubstring {
if len(errs) != 0 && !strings.Contains(utilerrors.NewAggregate(errs).Error(), curr) {
t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, utilerrors.NewAggregate(errs))
}
}
} else {
if len(errs) != 0 {
t.Errorf("Unexpected error: %v", utilerrors.NewAggregate(errs))
}
}
}
func (c configValidationTest) testConfirmUsable(contextName string, t *testing.T) {
err := ConfirmUsable(*c.config, contextName)
if len(c.expectedErrorSubstring) != 0 {
if err == nil {
t.Errorf("Expected error containing: %v", c.expectedErrorSubstring)
} else {
for _, curr := range c.expectedErrorSubstring {
if err != nil && !strings.Contains(err.Error(), curr) {
t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, err)
}
}
}
} else {
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
}
}
func (c configValidationTest) testConfig(t *testing.T) {
err := Validate(*c.config)
if len(c.expectedErrorSubstring) != 0 {
if err == nil {
t.Errorf("Expected error containing: %v", c.expectedErrorSubstring)
} else {
for _, curr := range c.expectedErrorSubstring {
if err != nil && !strings.Contains(err.Error(), curr) {
t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, err)
}
}
if !IsConfigurationInvalid(err) {
t.Errorf("all errors should be configuration invalid: %v", err)
}
}
} else {
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
}
}
func (c configValidationTest) testCluster(clusterName string, t *testing.T) {
errs := validateClusterInfo(clusterName, *c.config.Clusters[clusterName])
if len(c.expectedErrorSubstring) != 0 {
if len(errs) == 0 {
t.Errorf("Expected error containing: %v", c.expectedErrorSubstring)
}
for _, curr := range c.expectedErrorSubstring {
if len(errs) != 0 && !strings.Contains(utilerrors.NewAggregate(errs).Error(), curr) {
t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, utilerrors.NewAggregate(errs))
}
}
} else {
if len(errs) != 0 {
t.Errorf("Unexpected error: %v", utilerrors.NewAggregate(errs))
}
}
}
func (c configValidationTest) testAuthInfo(authInfoName string, t *testing.T) {
errs := validateAuthInfo(authInfoName, *c.config.AuthInfos[authInfoName])
if len(c.expectedErrorSubstring) != 0 {
if len(errs) == 0 {
t.Errorf("Expected error containing: %v", c.expectedErrorSubstring)
}
for _, curr := range c.expectedErrorSubstring {
if len(errs) != 0 && !strings.Contains(utilerrors.NewAggregate(errs).Error(), curr) {
t.Errorf("Expected error containing: %v, but got %v", c.expectedErrorSubstring, utilerrors.NewAggregate(errs))
}
}
} else {
if len(errs) != 0 {
t.Errorf("Unexpected error: %v", utilerrors.NewAggregate(errs))
}
}
}

View file

@ -153,12 +153,18 @@ func JobHasDesiredParallelism(c ExtensionsInterface, job *extensions.Job) wait.C
// the desired replica count for a deployment equals its updated replicas count.
// (non-terminated pods that have the desired template spec).
func DeploymentHasDesiredReplicas(c ExtensionsInterface, deployment *extensions.Deployment) wait.ConditionFunc {
// If we're given a deployment where the status lags the spec, it either
// means that the deployment is stale, or that the deployment manager hasn't
// noticed the update yet. Polling status.Replicas is not safe in the latter
// case.
desiredGeneration := deployment.Generation
return func() (bool, error) {
deployment, err := c.Deployments(deployment.Namespace).Get(deployment.Name)
if err != nil {
return false, err
}
return deployment.Status.UpdatedReplicas == deployment.Spec.Replicas, nil
return deployment.Status.ObservedGeneration >= desiredGeneration &&
deployment.Status.UpdatedReplicas == deployment.Spec.Replicas, nil
}
}

View file

@ -1,71 +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 (
"fmt"
"testing"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/util/wait"
)
func TestRetryOnConflict(t *testing.T) {
opts := wait.Backoff{Factor: 1.0, Steps: 3}
conflictErr := errors.NewConflict(unversioned.GroupResource{Resource: "test"}, "other", nil)
// never returns
err := RetryOnConflict(opts, func() error {
return conflictErr
})
if err != conflictErr {
t.Errorf("unexpected error: %v", err)
}
// returns immediately
i := 0
err = RetryOnConflict(opts, func() error {
i++
return nil
})
if err != nil || i != 1 {
t.Errorf("unexpected error: %v", err)
}
// returns immediately on error
testErr := fmt.Errorf("some other error")
err = RetryOnConflict(opts, func() error {
return testErr
})
if err != testErr {
t.Errorf("unexpected error: %v", err)
}
// keeps retrying
i = 0
err = RetryOnConflict(opts, func() error {
if i < 2 {
i++
return errors.NewConflict(unversioned.GroupResource{Resource: "test"}, "other", nil)
}
return nil
})
if err != nil || i != 2 {
t.Errorf("unexpected error: %v", err)
}
}

View file

@ -1,200 +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"
"net/http"
"net/http/httptest"
"net/url"
"path"
"reflect"
"strconv"
"strings"
"testing"
"time"
cadvisorapi "github.com/google/cadvisor/info/v1"
cadvisorapitest "github.com/google/cadvisor/info/v1/test"
)
func testHTTPContainerInfoGetter(
req *cadvisorapi.ContainerInfoRequest,
cinfo *cadvisorapi.ContainerInfo,
podID string,
containerID string,
status int,
t *testing.T,
) {
expectedPath := "/stats"
if len(podID) > 0 && len(containerID) > 0 {
expectedPath = path.Join(expectedPath, podID, containerID)
}
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if status != 0 {
w.WriteHeader(status)
}
if strings.TrimRight(r.URL.Path, "/") != strings.TrimRight(expectedPath, "/") {
t.Fatalf("Received request to an invalid path. Should be %v. got %v",
expectedPath, r.URL.Path)
}
var receivedReq cadvisorapi.ContainerInfoRequest
err := json.NewDecoder(r.Body).Decode(&receivedReq)
if err != nil {
t.Fatal(err)
}
// Note: This will not make a deep copy of req.
// So changing req after Get*Info would be a race.
expectedReq := req
// Fill any empty fields with default value
if !expectedReq.Equals(receivedReq) {
t.Errorf("received wrong request")
}
err = json.NewEncoder(w).Encode(cinfo)
if err != nil {
t.Fatal(err)
}
}))
// TODO: Uncomment when fix #19254
// defer ts.Close()
hostURL, err := url.Parse(ts.URL)
if err != nil {
t.Fatal(err)
}
parts := strings.Split(hostURL.Host, ":")
port, err := strconv.Atoi(parts[1])
if err != nil {
t.Fatal(err)
}
containerInfoGetter := &HTTPContainerInfoGetter{
Client: http.DefaultClient,
Port: port,
}
var receivedContainerInfo *cadvisorapi.ContainerInfo
if len(podID) > 0 && len(containerID) > 0 {
receivedContainerInfo, err = containerInfoGetter.GetContainerInfo(parts[0], podID, containerID, req)
} else {
receivedContainerInfo, err = containerInfoGetter.GetRootInfo(parts[0], req)
}
if status == 0 || status == http.StatusOK {
if err != nil {
t.Errorf("received unexpected error: %v", err)
}
if !receivedContainerInfo.Eq(cinfo) {
t.Error("received unexpected container info")
}
} else {
if err == nil {
t.Error("did not receive expected error.")
}
}
}
func TestHTTPContainerInfoGetterGetContainerInfoSuccessfully(t *testing.T) {
req := &cadvisorapi.ContainerInfoRequest{
NumStats: 10,
}
cinfo := cadvisorapitest.GenerateRandomContainerInfo(
"dockerIDWhichWillNotBeChecked", // docker ID
2, // Number of cores
req,
1*time.Second,
)
testHTTPContainerInfoGetter(req, cinfo, "somePodID", "containerNameInK8S", 0, t)
}
func TestHTTPContainerInfoGetterGetRootInfoSuccessfully(t *testing.T) {
req := &cadvisorapi.ContainerInfoRequest{
NumStats: 10,
}
cinfo := cadvisorapitest.GenerateRandomContainerInfo(
"dockerIDWhichWillNotBeChecked", // docker ID
2, // Number of cores
req,
1*time.Second,
)
testHTTPContainerInfoGetter(req, cinfo, "", "", 0, t)
}
func TestHTTPContainerInfoGetterGetContainerInfoWithError(t *testing.T) {
req := &cadvisorapi.ContainerInfoRequest{
NumStats: 10,
}
cinfo := cadvisorapitest.GenerateRandomContainerInfo(
"dockerIDWhichWillNotBeChecked", // docker ID
2, // Number of cores
req,
1*time.Second,
)
testHTTPContainerInfoGetter(req, cinfo, "somePodID", "containerNameInK8S", http.StatusNotFound, t)
}
func TestHTTPContainerInfoGetterGetRootInfoWithError(t *testing.T) {
req := &cadvisorapi.ContainerInfoRequest{
NumStats: 10,
}
cinfo := cadvisorapitest.GenerateRandomContainerInfo(
"dockerIDWhichWillNotBeChecked", // docker ID
2, // Number of cores
req,
1*time.Second,
)
testHTTPContainerInfoGetter(req, cinfo, "", "", http.StatusNotFound, t)
}
func TestHTTPGetMachineInfo(t *testing.T) {
mspec := &cadvisorapi.MachineInfo{
NumCores: 4,
MemoryCapacity: 2048,
}
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
err := json.NewEncoder(w).Encode(mspec)
if err != nil {
t.Fatal(err)
}
}))
// TODO: Uncomment when fix #19254
// defer ts.Close()
hostURL, err := url.Parse(ts.URL)
if err != nil {
t.Fatal(err)
}
parts := strings.Split(hostURL.Host, ":")
port, err := strconv.Atoi(parts[1])
if err != nil {
t.Fatal(err)
}
containerInfoGetter := &HTTPContainerInfoGetter{
Client: http.DefaultClient,
Port: port,
}
received, err := containerInfoGetter.GetMachineInfo(parts[0])
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(received, mspec) {
t.Errorf("received wrong machine spec")
}
}

View file

@ -1,199 +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_test
import (
. "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/testclient/simple"
)
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/apis/extensions"
)
func getDSResourceName() string {
return "daemonsets"
}
func TestListDaemonSets(t *testing.T) {
ns := api.NamespaceAll
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: testapi.Extensions.ResourcePath(getDSResourceName(), ns, ""),
},
Response: simple.Response{StatusCode: 200,
Body: &extensions.DaemonSetList{
Items: []extensions.DaemonSet{
{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.DaemonSetSpec{
Template: api.PodTemplateSpec{},
},
},
},
},
},
}
receivedDSs, err := c.Setup(t).Extensions().DaemonSets(ns).List(api.ListOptions{})
defer c.Close()
c.Validate(t, receivedDSs, err)
}
func TestGetDaemonSet(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{
Request: simple.Request{Method: "GET", Path: testapi.Extensions.ResourcePath(getDSResourceName(), ns, "foo"), Query: simple.BuildQueryValues(nil)},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.DaemonSet{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.DaemonSetSpec{
Template: api.PodTemplateSpec{},
},
},
},
}
receivedDaemonSet, err := c.Setup(t).Extensions().DaemonSets(ns).Get("foo")
defer c.Close()
c.Validate(t, receivedDaemonSet, err)
}
func TestGetDaemonSetWithNoName(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{Error: true}
receivedPod, err := c.Setup(t).Extensions().DaemonSets(ns).Get("")
defer c.Close()
if (err != nil) && (err.Error() != simple.NameRequiredError) {
t.Errorf("Expected error: %v, but got %v", simple.NameRequiredError, err)
}
c.Validate(t, receivedPod, err)
}
func TestUpdateDaemonSet(t *testing.T) {
ns := api.NamespaceDefault
requestDaemonSet := &extensions.DaemonSet{
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
}
c := &simple.Client{
Request: simple.Request{Method: "PUT", Path: testapi.Extensions.ResourcePath(getDSResourceName(), ns, "foo"), Query: simple.BuildQueryValues(nil)},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.DaemonSet{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.DaemonSetSpec{
Template: api.PodTemplateSpec{},
},
},
},
}
receivedDaemonSet, err := c.Setup(t).Extensions().DaemonSets(ns).Update(requestDaemonSet)
defer c.Close()
c.Validate(t, receivedDaemonSet, err)
}
func TestUpdateDaemonSetUpdateStatus(t *testing.T) {
ns := api.NamespaceDefault
requestDaemonSet := &extensions.DaemonSet{
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
}
c := &simple.Client{
Request: simple.Request{Method: "PUT", Path: testapi.Extensions.ResourcePath(getDSResourceName(), ns, "foo") + "/status", Query: simple.BuildQueryValues(nil)},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.DaemonSet{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.DaemonSetSpec{
Template: api.PodTemplateSpec{},
},
Status: extensions.DaemonSetStatus{},
},
},
}
receivedDaemonSet, err := c.Setup(t).Extensions().DaemonSets(ns).UpdateStatus(requestDaemonSet)
defer c.Close()
c.Validate(t, receivedDaemonSet, err)
}
func TestDeleteDaemon(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{
Request: simple.Request{Method: "DELETE", Path: testapi.Extensions.ResourcePath(getDSResourceName(), ns, "foo"), Query: simple.BuildQueryValues(nil)},
Response: simple.Response{StatusCode: 200},
}
err := c.Setup(t).Extensions().DaemonSets(ns).Delete("foo")
defer c.Close()
c.Validate(t, nil, err)
}
func TestCreateDaemonSet(t *testing.T) {
ns := api.NamespaceDefault
requestDaemonSet := &extensions.DaemonSet{
ObjectMeta: api.ObjectMeta{Name: "foo"},
}
c := &simple.Client{
Request: simple.Request{Method: "POST", Path: testapi.Extensions.ResourcePath(getDSResourceName(), ns, ""), Body: requestDaemonSet, Query: simple.BuildQueryValues(nil)},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.DaemonSet{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.DaemonSetSpec{
Template: api.PodTemplateSpec{},
},
},
},
}
receivedDaemonSet, err := c.Setup(t).Extensions().DaemonSets(ns).Create(requestDaemonSet)
defer c.Close()
c.Validate(t, receivedDaemonSet, err)
}

View file

@ -1,240 +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_test
import (
. "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/testclient/simple"
)
import (
"net/http"
"net/url"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/labels"
)
func getDeploymentsResourceName() string {
return "deployments"
}
func TestDeploymentCreate(t *testing.T) {
ns := api.NamespaceDefault
deployment := extensions.Deployment{
ObjectMeta: api.ObjectMeta{
Name: "abc",
Namespace: ns,
},
}
c := &simple.Client{
Request: simple.Request{
Method: "POST",
Path: testapi.Extensions.ResourcePath(getDeploymentsResourceName(), ns, ""),
Query: simple.BuildQueryValues(nil),
Body: &deployment,
},
Response: simple.Response{StatusCode: 200, Body: &deployment},
}
response, err := c.Setup(t).Deployments(ns).Create(&deployment)
defer c.Close()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
c.Validate(t, response, err)
}
func TestDeploymentGet(t *testing.T) {
ns := api.NamespaceDefault
deployment := &extensions.Deployment{
ObjectMeta: api.ObjectMeta{
Name: "abc",
Namespace: ns,
},
}
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: testapi.Extensions.ResourcePath(getDeploymentsResourceName(), ns, "abc"),
Query: simple.BuildQueryValues(nil),
Body: nil,
},
Response: simple.Response{StatusCode: 200, Body: deployment},
}
response, err := c.Setup(t).Deployments(ns).Get("abc")
defer c.Close()
c.Validate(t, response, err)
}
func TestDeploymentList(t *testing.T) {
ns := api.NamespaceDefault
deploymentList := &extensions.DeploymentList{
Items: []extensions.Deployment{
{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: ns,
},
},
},
}
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: testapi.Extensions.ResourcePath(getDeploymentsResourceName(), ns, ""),
Query: simple.BuildQueryValues(nil),
Body: nil,
},
Response: simple.Response{StatusCode: 200, Body: deploymentList},
}
response, err := c.Setup(t).Deployments(ns).List(api.ListOptions{})
defer c.Close()
c.Validate(t, response, err)
}
func TestDeploymentUpdate(t *testing.T) {
ns := api.NamespaceDefault
deployment := &extensions.Deployment{
ObjectMeta: api.ObjectMeta{
Name: "abc",
Namespace: ns,
ResourceVersion: "1",
},
}
c := &simple.Client{
Request: simple.Request{
Method: "PUT",
Path: testapi.Extensions.ResourcePath(getDeploymentsResourceName(), ns, "abc"),
Query: simple.BuildQueryValues(nil),
},
Response: simple.Response{StatusCode: 200, Body: deployment},
}
response, err := c.Setup(t).Deployments(ns).Update(deployment)
defer c.Close()
c.Validate(t, response, err)
}
func TestDeploymentUpdateStatus(t *testing.T) {
ns := api.NamespaceDefault
deployment := &extensions.Deployment{
ObjectMeta: api.ObjectMeta{
Name: "abc",
Namespace: ns,
ResourceVersion: "1",
},
}
c := &simple.Client{
Request: simple.Request{
Method: "PUT",
Path: testapi.Extensions.ResourcePath(getDeploymentsResourceName(), ns, "abc") + "/status",
Query: simple.BuildQueryValues(nil),
},
Response: simple.Response{StatusCode: 200, Body: deployment},
}
response, err := c.Setup(t).Deployments(ns).UpdateStatus(deployment)
defer c.Close()
c.Validate(t, response, err)
}
func TestDeploymentDelete(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{
Request: simple.Request{
Method: "DELETE",
Path: testapi.Extensions.ResourcePath(getDeploymentsResourceName(), ns, "foo"),
Query: simple.BuildQueryValues(nil),
},
Response: simple.Response{StatusCode: 200},
}
err := c.Setup(t).Deployments(ns).Delete("foo", nil)
defer c.Close()
c.Validate(t, nil, err)
}
func TestDeploymentWatch(t *testing.T) {
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: testapi.Extensions.ResourcePathWithPrefix("watch", getDeploymentsResourceName(), "", ""),
Query: url.Values{"resourceVersion": []string{}},
},
Response: simple.Response{StatusCode: 200},
}
_, err := c.Setup(t).Deployments(api.NamespaceAll).Watch(api.ListOptions{})
defer c.Close()
c.Validate(t, nil, err)
}
func TestListDeploymentsLabels(t *testing.T) {
ns := api.NamespaceDefault
labelSelectorQueryParamName := unversioned.LabelSelectorQueryParam(testapi.Extensions.GroupVersion().String())
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: testapi.Extensions.ResourcePath("deployments", ns, ""),
Query: simple.BuildQueryValues(url.Values{labelSelectorQueryParamName: []string{"foo=bar,name=baz"}})},
Response: simple.Response{
StatusCode: http.StatusOK,
Body: &extensions.DeploymentList{
Items: []extensions.Deployment{
{
ObjectMeta: api.ObjectMeta{
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
},
},
},
},
}
c.Setup(t)
defer c.Close()
c.QueryValidator[labelSelectorQueryParamName] = simple.ValidateLabels
selector := labels.Set{"foo": "bar", "name": "baz"}.AsSelector()
options := api.ListOptions{LabelSelector: selector}
receivedPodList, err := c.Deployments(ns).List(options)
c.Validate(t, receivedPodList, err)
}
func TestDeploymentRollback(t *testing.T) {
ns := api.NamespaceDefault
deploymentRollback := &extensions.DeploymentRollback{
Name: "abc",
UpdatedAnnotations: map[string]string{},
RollbackTo: extensions.RollbackConfig{Revision: 1},
}
c := &simple.Client{
Request: simple.Request{
Method: "POST",
Path: testapi.Extensions.ResourcePath(getDeploymentsResourceName(), ns, "abc") + "/rollback",
Query: simple.BuildQueryValues(nil),
Body: deploymentRollback,
},
Response: simple.Response{StatusCode: http.StatusOK},
}
err := c.Setup(t).Deployments(ns).Rollback(deploymentRollback)
defer c.Close()
c.ValidateCommon(t, err)
}

View file

@ -1,75 +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_test
import (
. "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/testclient/simple"
)
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
)
func TestListEndpoints(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{
Request: simple.Request{Method: "GET", Path: testapi.Default.ResourcePath("endpoints", ns, ""), Query: simple.BuildQueryValues(nil)},
Response: simple.Response{StatusCode: 200,
Body: &api.EndpointsList{
Items: []api.Endpoints{
{
ObjectMeta: api.ObjectMeta{Name: "endpoint-1"},
Subsets: []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "10.245.1.2"}, {IP: "10.245.1.3"}},
Ports: []api.EndpointPort{{Port: 8080}},
}},
},
},
},
},
}
receivedEndpointsList, err := c.Setup(t).Endpoints(ns).List(api.ListOptions{})
defer c.Close()
c.Validate(t, receivedEndpointsList, err)
}
func TestGetEndpoints(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{
Request: simple.Request{Method: "GET", Path: testapi.Default.ResourcePath("endpoints", ns, "endpoint-1"), Query: simple.BuildQueryValues(nil)},
Response: simple.Response{StatusCode: 200, Body: &api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "endpoint-1"}}},
}
response, err := c.Setup(t).Endpoints(ns).Get("endpoint-1")
defer c.Close()
c.Validate(t, response, err)
}
func TestGetEndpointWithNoName(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{Error: true}
receivedPod, err := c.Setup(t).Endpoints(ns).Get("")
defer c.Close()
if (err != nil) && (err.Error() != simple.NameRequiredError) {
t.Errorf("Expected error: %v, but got %v", simple.NameRequiredError, err)
}
c.Validate(t, receivedPod, err)
}

View file

@ -1,205 +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_test
import (
. "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/testclient/simple"
)
import (
"net/url"
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned"
)
func TestEventSearch(t *testing.T) {
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: testapi.Default.ResourcePath("events", "baz", ""),
Query: url.Values{
unversioned.FieldSelectorQueryParam(testapi.Default.GroupVersion().String()): []string{
GetInvolvedObjectNameFieldLabel(testapi.Default.GroupVersion().String()) + "=foo,",
"involvedObject.namespace=baz,",
"involvedObject.kind=Pod",
},
unversioned.LabelSelectorQueryParam(testapi.Default.GroupVersion().String()): []string{},
},
},
Response: simple.Response{StatusCode: 200, Body: &api.EventList{}},
}
eventList, err := c.Setup(t).Events("baz").Search(
&api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: "baz",
SelfLink: testapi.Default.SelfLink("pods", ""),
},
},
)
defer c.Close()
c.Validate(t, eventList, err)
}
func TestEventCreate(t *testing.T) {
objReference := &api.ObjectReference{
Kind: "foo",
Namespace: "nm",
Name: "objref1",
UID: "uid",
APIVersion: "apiv1",
ResourceVersion: "1",
}
timeStamp := unversioned.Now()
event := &api.Event{
ObjectMeta: api.ObjectMeta{
Namespace: api.NamespaceDefault,
},
InvolvedObject: *objReference,
FirstTimestamp: timeStamp,
LastTimestamp: timeStamp,
Count: 1,
Type: api.EventTypeNormal,
}
c := &simple.Client{
Request: simple.Request{
Method: "POST",
Path: testapi.Default.ResourcePath("events", api.NamespaceDefault, ""),
Body: event,
},
Response: simple.Response{StatusCode: 200, Body: event},
}
response, err := c.Setup(t).Events(api.NamespaceDefault).Create(event)
defer c.Close()
if err != nil {
t.Fatalf("%v should be nil.", err)
}
if e, a := *objReference, response.InvolvedObject; !reflect.DeepEqual(e, a) {
t.Errorf("%#v != %#v.", e, a)
}
}
func TestEventGet(t *testing.T) {
objReference := &api.ObjectReference{
Kind: "foo",
Namespace: "nm",
Name: "objref1",
UID: "uid",
APIVersion: "apiv1",
ResourceVersion: "1",
}
timeStamp := unversioned.Now()
event := &api.Event{
ObjectMeta: api.ObjectMeta{
Namespace: "other",
},
InvolvedObject: *objReference,
FirstTimestamp: timeStamp,
LastTimestamp: timeStamp,
Count: 1,
Type: api.EventTypeNormal,
}
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: testapi.Default.ResourcePath("events", "other", "1"),
Body: nil,
},
Response: simple.Response{StatusCode: 200, Body: event},
}
response, err := c.Setup(t).Events("other").Get("1")
defer c.Close()
if err != nil {
t.Fatalf("%v should be nil.", err)
}
if e, r := event.InvolvedObject, response.InvolvedObject; !reflect.DeepEqual(e, r) {
t.Errorf("%#v != %#v.", e, r)
}
}
func TestEventList(t *testing.T) {
ns := api.NamespaceDefault
objReference := &api.ObjectReference{
Kind: "foo",
Namespace: ns,
Name: "objref1",
UID: "uid",
APIVersion: "apiv1",
ResourceVersion: "1",
}
timeStamp := unversioned.Now()
eventList := &api.EventList{
Items: []api.Event{
{
InvolvedObject: *objReference,
FirstTimestamp: timeStamp,
LastTimestamp: timeStamp,
Count: 1,
Type: api.EventTypeNormal,
},
},
}
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: testapi.Default.ResourcePath("events", ns, ""),
Body: nil,
},
Response: simple.Response{StatusCode: 200, Body: eventList},
}
response, err := c.Setup(t).Events(ns).List(api.ListOptions{})
defer c.Close()
if err != nil {
t.Errorf("%#v should be nil.", err)
}
if len(response.Items) != 1 {
t.Errorf("%#v response.Items should have len 1.", response.Items)
}
responseEvent := response.Items[0]
if e, r := eventList.Items[0].InvolvedObject,
responseEvent.InvolvedObject; !reflect.DeepEqual(e, r) {
t.Errorf("%#v != %#v.", e, r)
}
}
func TestEventDelete(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{
Request: simple.Request{
Method: "DELETE",
Path: testapi.Default.ResourcePath("events", ns, "foo"),
},
Response: simple.Response{StatusCode: 200},
}
err := c.Setup(t).Events(ns).Delete("foo")
defer c.Close()
c.Validate(t, nil, err)
}

View file

@ -20,6 +20,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/restclient"
)
// Interface holds the experimental methods for clients of Kubernetes
@ -42,7 +43,7 @@ type ExtensionsInterface interface {
// Features of Extensions group are not supported and may be changed or removed in
// incompatible ways at any time.
type ExtensionsClient struct {
*RESTClient
*restclient.RESTClient
}
func (c *ExtensionsClient) PodSecurityPolicies() PodSecurityPolicyInterface {
@ -85,12 +86,12 @@ func (c *ExtensionsClient) ReplicaSets(namespace string) ReplicaSetInterface {
// provides access to experimental Kubernetes features.
// Features of Extensions group are not supported and may be changed or removed in
// incompatible ways at any time.
func NewExtensions(c *Config) (*ExtensionsClient, error) {
func NewExtensions(c *restclient.Config) (*ExtensionsClient, error) {
config := *c
if err := setExtensionsDefaults(&config); err != nil {
return nil, err
}
client, err := RESTClientFor(&config)
client, err := restclient.RESTClientFor(&config)
if err != nil {
return nil, err
}
@ -101,7 +102,7 @@ func NewExtensions(c *Config) (*ExtensionsClient, error) {
// panics if there is an error in the config.
// Features of Extensions group are not supported and may be changed or removed in
// incompatible ways at any time.
func NewExtensionsOrDie(c *Config) *ExtensionsClient {
func NewExtensionsOrDie(c *restclient.Config) *ExtensionsClient {
client, err := NewExtensions(c)
if err != nil {
panic(err)
@ -109,7 +110,7 @@ func NewExtensionsOrDie(c *Config) *ExtensionsClient {
return client
}
func setExtensionsDefaults(config *Config) error {
func setExtensionsDefaults(config *restclient.Config) error {
// if experimental group is not registered, return an error
g, err := registered.Group(extensions.GroupName)
if err != nil {
@ -117,7 +118,7 @@ func setExtensionsDefaults(config *Config) error {
}
config.APIPath = defaultAPIPath
if config.UserAgent == "" {
config.UserAgent = DefaultKubernetesUserAgent()
config.UserAgent = restclient.DefaultKubernetesUserAgent()
}
// TODO: Unconditionally set the config.Version, until we fix the config.
//if config.Version == "" {

View file

@ -1,85 +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.
*/
// This is made a separate package and should only be imported by tests, because
// it imports testapi
package fake
import (
"net/http"
"net/url"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/runtime"
)
func CreateHTTPClient(roundTripper func(*http.Request) (*http.Response, error)) *http.Client {
return &http.Client{
Transport: roundTripperFunc(roundTripper),
}
}
type roundTripperFunc func(*http.Request) (*http.Response, error)
func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return f(req)
}
// RESTClient provides a fake RESTClient interface.
type RESTClient struct {
Client *http.Client
Codec runtime.Codec
Req *http.Request
Resp *http.Response
Err error
}
func (c *RESTClient) Get() *unversioned.Request {
return c.request("GET")
}
func (c *RESTClient) Put() *unversioned.Request {
return c.request("PUT")
}
func (c *RESTClient) Patch(_ api.PatchType) *unversioned.Request {
return c.request("PATCH")
}
func (c *RESTClient) Post() *unversioned.Request {
return c.request("POST")
}
func (c *RESTClient) Delete() *unversioned.Request {
return c.request("DELETE")
}
func (c *RESTClient) request(verb string) *unversioned.Request {
return unversioned.NewRequest(c, verb, &url.URL{Host: "localhost"}, "", unversioned.ContentConfig{GroupVersion: testapi.Default.GroupVersion(), Codec: c.Codec}, nil, nil)
}
func (c *RESTClient) Do(req *http.Request) (*http.Response, error) {
if c.Err != nil {
return nil, c.Err
}
c.Req = req
if c.Client != nil {
return c.Client.Do(req)
}
return c.Resp, nil
}

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 unversioned
import (
"testing"
"time"
"k8s.io/kubernetes/pkg/util/sets"
)
type fakeFlagSet struct {
t *testing.T
set sets.String
}
func (f *fakeFlagSet) StringVar(p *string, name, value, usage string) {
if p == nil {
f.t.Errorf("unexpected nil pointer")
}
if usage == "" {
f.t.Errorf("unexpected empty usage")
}
f.set.Insert(name)
}
func (f *fakeFlagSet) BoolVar(p *bool, name string, value bool, usage string) {
if p == nil {
f.t.Errorf("unexpected nil pointer")
}
if usage == "" {
f.t.Errorf("unexpected empty usage")
}
f.set.Insert(name)
}
func (f *fakeFlagSet) UintVar(p *uint, name string, value uint, usage string) {
if p == nil {
f.t.Errorf("unexpected nil pointer")
}
if usage == "" {
f.t.Errorf("unexpected empty usage")
}
f.set.Insert(name)
}
func (f *fakeFlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
if p == nil {
f.t.Errorf("unexpected nil pointer")
}
if usage == "" {
f.t.Errorf("unexpected empty usage")
}
f.set.Insert(name)
}
func (f *fakeFlagSet) IntVar(p *int, name string, value int, usage string) {
if p == nil {
f.t.Errorf("unexpected nil pointer")
}
if usage == "" {
f.t.Errorf("unexpected empty usage")
}
f.set.Insert(name)
}

View file

@ -17,26 +17,17 @@ limitations under the License.
package unversioned
import (
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"os"
"path"
"reflect"
gruntime "runtime"
"strings"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"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/util"
"k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/client/typed/discovery"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/version"
)
@ -46,112 +37,22 @@ const (
defaultAPIPath = "/apis"
)
// Config holds the common attributes that can be passed to a Kubernetes client on
// initialization.
type Config struct {
// Host must be a host string, a host:port pair, or a URL to the base of the apiserver.
// If a URL is given then the (optional) Path of that URL represents a prefix that must
// be appended to all request URIs used to access the apiserver. This allows a frontend
// proxy to easily relocate all of the apiserver endpoints.
Host string
// APIPath is a sub-path that points to an API root.
APIPath string
// Prefix is the sub path of the server. If not specified, the client will set
// a default value. Use "/" to indicate the server root should be used
Prefix string
// ContentConfig contains settings that affect how objects are transformed when
// sent to the server.
ContentConfig
// Server requires Basic authentication
Username string
Password string
// Server requires Bearer authentication. This client will not attempt to use
// refresh tokens for an OAuth2 flow.
// TODO: demonstrate an OAuth2 compatible client.
BearerToken string
// TLSClientConfig contains settings to enable transport layer security
TLSClientConfig
// Server should be accessed without verifying the TLS
// certificate. For testing only.
Insecure bool
// UserAgent is an optional field that specifies the caller of this request.
UserAgent string
// Transport may be used for custom HTTP behavior. This attribute may not
// be specified with the TLS client certificate options. Use WrapTransport
// for most client level operations.
Transport http.RoundTripper
// WrapTransport will be invoked for custom HTTP behavior after the underlying
// transport is initialized (either the transport created from TLSClientConfig,
// Transport, or http.DefaultTransport). The config may layer other RoundTrippers
// on top of the returned RoundTripper.
WrapTransport func(rt http.RoundTripper) http.RoundTripper
// QPS indicates the maximum QPS to the master from this client. If zero, QPS is unlimited.
QPS float32
// Maximum burst for throttle
Burst int
}
// TLSClientConfig contains settings to enable transport layer security
type TLSClientConfig struct {
// Server requires TLS client certificate authentication
CertFile string
// Server requires TLS client certificate authentication
KeyFile string
// Trusted root certificates for server
CAFile string
// CertData holds PEM-encoded bytes (typically read from a client certificate file).
// CertData takes precedence over CertFile
CertData []byte
// KeyData holds PEM-encoded bytes (typically read from a client certificate key file).
// KeyData takes precedence over KeyFile
KeyData []byte
// CAData holds PEM-encoded bytes (typically read from a root certificates bundle).
// CAData takes precedence over CAFile
CAData []byte
}
type ContentConfig struct {
// ContentType specifies the wire format used to communicate with the server.
// This value will be set as the Accept header on requests made to the server, and
// as the default content type on any object sent to the server. If not set,
// "application/json" is used.
ContentType string
// GroupVersion is the API version to talk to. Must be provided when initializing
// a RESTClient directly. When initializing a Client, will be set with the default
// code version.
GroupVersion *unversioned.GroupVersion
// Codec specifies the encoding and decoding behavior for runtime.Objects passed
// to a RESTClient or Client. Required when initializing a RESTClient, optional
// when initializing a Client.
Codec runtime.Codec
}
// New creates a Kubernetes client for the given config. This client works with pods,
// replication controllers, daemons, and services. It allows operations such as list, get, update
// and delete on these objects. An error is returned if the provided configuration
// is not valid.
func New(c *Config) (*Client, error) {
func New(c *restclient.Config) (*Client, error) {
config := *c
if err := SetKubernetesDefaults(&config); err != nil {
return nil, err
}
client, err := RESTClientFor(&config)
client, err := restclient.RESTClientFor(&config)
if err != nil {
return nil, err
}
discoveryConfig := *c
discoveryClient, err := NewDiscoveryClientForConfig(&discoveryConfig)
discoveryClient, err := discovery.NewDiscoveryClientForConfig(&discoveryConfig)
if err != nil {
return nil, err
}
@ -165,6 +66,15 @@ func New(c *Config) (*Client, error) {
}
}
var batchClient *BatchClient
if registered.IsRegistered(batch.GroupName) {
batchConfig := *c
batchClient, err = NewBatch(&batchConfig)
if err != nil {
return nil, err
}
}
var extensionsClient *ExtensionsClient
if registered.IsRegistered(extensions.GroupName) {
extensionsConfig := *c
@ -174,13 +84,13 @@ func New(c *Config) (*Client, error) {
}
}
return &Client{RESTClient: client, AutoscalingClient: autoscalingClient, ExtensionsClient: extensionsClient, DiscoveryClient: discoveryClient}, nil
return &Client{RESTClient: client, AutoscalingClient: autoscalingClient, BatchClient: batchClient, ExtensionsClient: extensionsClient, DiscoveryClient: discoveryClient}, nil
}
// MatchesServerVersion queries the server to compares the build version
// (git hash) of the client with the server's build version. It returns an error
// if it failed to contact the server or if the versions are not an exact match.
func MatchesServerVersion(client *Client, c *Config) error {
func MatchesServerVersion(client *Client, c *restclient.Config) error {
var err error
if client == nil {
client, err = New(c)
@ -200,66 +110,6 @@ func MatchesServerVersion(client *Client, c *Config) error {
return nil
}
func ExtractGroupVersions(l *unversioned.APIGroupList) []string {
var groupVersions []string
for _, g := range l.Groups {
for _, gv := range g.Versions {
groupVersions = append(groupVersions, gv.GroupVersion)
}
}
return groupVersions
}
// ServerAPIVersions returns the GroupVersions supported by the API server.
// It creates a RESTClient based on the passed in config, but it doesn't rely
// on the Version and Codec of the config, because it uses AbsPath and
// takes the raw response.
func ServerAPIVersions(c *Config) (groupVersions []string, err error) {
transport, err := TransportFor(c)
if err != nil {
return nil, err
}
client := http.Client{Transport: transport}
configCopy := *c
configCopy.GroupVersion = nil
configCopy.APIPath = ""
baseURL, _, err := defaultServerUrlFor(&configCopy)
if err != nil {
return nil, err
}
// Get the groupVersions exposed at /api
originalPath := baseURL.Path
baseURL.Path = path.Join(originalPath, legacyAPIPath)
resp, err := client.Get(baseURL.String())
if err != nil {
return nil, err
}
var v unversioned.APIVersions
defer resp.Body.Close()
err = json.NewDecoder(resp.Body).Decode(&v)
if err != nil {
return nil, fmt.Errorf("unexpected error: %v", err)
}
groupVersions = append(groupVersions, v.Versions...)
// Get the groupVersions exposed at /apis
baseURL.Path = path.Join(originalPath, defaultAPIPath)
resp2, err := client.Get(baseURL.String())
if err != nil {
return nil, err
}
var apiGroupList unversioned.APIGroupList
defer resp2.Body.Close()
err = json.NewDecoder(resp2.Body).Decode(&apiGroupList)
if err != nil {
return nil, fmt.Errorf("unexpected error: %v", err)
}
groupVersions = append(groupVersions, ExtractGroupVersions(&apiGroupList)...)
return groupVersions, nil
}
// NegotiateVersion queries the server's supported api versions to find
// a version that both client and server support.
// - If no version is provided, try registered client versions in order of
@ -269,7 +119,7 @@ func ServerAPIVersions(c *Config) (groupVersions []string, err error) {
// stderr and try client's registered versions in order of preference.
// - If version is config default, and the server does not support it,
// return an error.
func NegotiateVersion(client *Client, c *Config, requestedGV *unversioned.GroupVersion, clientRegisteredGVs []unversioned.GroupVersion) (*unversioned.GroupVersion, error) {
func NegotiateVersion(client *Client, c *restclient.Config, requestedGV *unversioned.GroupVersion, clientRegisteredGVs []unversioned.GroupVersion) (*unversioned.GroupVersion, error) {
var err error
if client == nil {
client, err = New(c)
@ -287,7 +137,7 @@ func NegotiateVersion(client *Client, c *Config, requestedGV *unversioned.GroupV
// not a negotiation specific error.
return nil, err
}
versions := ExtractGroupVersions(groups)
versions := unversioned.ExtractGroupVersions(groups)
serverVersions := sets.String{}
for _, v := range versions {
serverVersions.Insert(v)
@ -339,7 +189,7 @@ func NegotiateVersion(client *Client, c *Config, requestedGV *unversioned.GroupV
}
// NewOrDie creates a Kubernetes client and panics if the provided API version is not recognized.
func NewOrDie(c *Config) *Client {
func NewOrDie(c *restclient.Config) *Client {
client, err := New(c)
if err != nil {
panic(err)
@ -347,39 +197,9 @@ func NewOrDie(c *Config) *Client {
return client
}
// InClusterConfig returns a config object which uses the service account
// kubernetes gives to pods. It's intended for clients that expect to be
// running inside a pod running on kuberenetes. It will return an error if
// called from a process not running in a kubernetes environment.
func InClusterConfig() (*Config, error) {
host, port := os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT")
if len(host) == 0 || len(port) == 0 {
return nil, fmt.Errorf("unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined")
}
token, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/" + api.ServiceAccountTokenKey)
if err != nil {
return nil, err
}
tlsClientConfig := TLSClientConfig{}
rootCAFile := "/var/run/secrets/kubernetes.io/serviceaccount/" + api.ServiceAccountRootCAKey
if _, err := util.CertPoolFromFile(rootCAFile); err != nil {
glog.Errorf("Expected to load root CA config from %s, but got err: %v", rootCAFile, err)
} else {
tlsClientConfig.CAFile = rootCAFile
}
return &Config{
// TODO: switch to using cluster DNS.
Host: "https://" + net.JoinHostPort(host, port),
BearerToken: string(token),
TLSClientConfig: tlsClientConfig,
}, nil
}
// NewInCluster is a shortcut for calling InClusterConfig() and then New().
func NewInCluster() (*Client, error) {
cc, err := InClusterConfig()
cc, err := restclient.InClusterConfig()
if err != nil {
return nil, err
}
@ -389,13 +209,10 @@ func NewInCluster() (*Client, error) {
// SetKubernetesDefaults sets default values on the provided client config for accessing the
// Kubernetes API or returns an error if any of the defaults are impossible or invalid.
// TODO: this method needs to be split into one that sets defaults per group, expected to be fix in PR "Refactoring clientcache.go and helper.go #14592"
func SetKubernetesDefaults(config *Config) error {
func SetKubernetesDefaults(config *restclient.Config) error {
if config.APIPath == "" {
config.APIPath = legacyAPIPath
}
if len(config.UserAgent) == 0 {
config.UserAgent = DefaultKubernetesUserAgent()
}
g, err := registered.Group(api.GroupName)
if err != nil {
return err
@ -406,233 +223,6 @@ func SetKubernetesDefaults(config *Config) error {
if config.Codec == nil {
config.Codec = api.Codecs.LegacyCodec(*config.GroupVersion)
}
if config.QPS == 0.0 {
config.QPS = 5.0
}
if config.Burst == 0 {
config.Burst = 10
}
return nil
}
// RESTClientFor returns a RESTClient that satisfies the requested attributes on a client Config
// object. Note that a RESTClient may require fields that are optional when initializing a Client.
// A RESTClient created by this method is generic - it expects to operate on an API that follows
// the Kubernetes conventions, but may not be the Kubernetes API.
func RESTClientFor(config *Config) (*RESTClient, error) {
if config.GroupVersion == nil {
return nil, fmt.Errorf("GroupVersion is required when initializing a RESTClient")
}
if config.Codec == nil {
return nil, fmt.Errorf("Codec is required when initializing a RESTClient")
}
baseURL, versionedAPIPath, err := defaultServerUrlFor(config)
if err != nil {
return nil, err
}
transport, err := TransportFor(config)
if err != nil {
return nil, err
}
var httpClient *http.Client
if transport != http.DefaultTransport {
httpClient = &http.Client{Transport: transport}
}
client := NewRESTClient(baseURL, versionedAPIPath, config.ContentConfig, config.QPS, config.Burst, httpClient)
return client, nil
}
// UnversionedRESTClientFor is the same as RESTClientFor, except that it allows
// the config.Version to be empty.
func UnversionedRESTClientFor(config *Config) (*RESTClient, error) {
if config.Codec == nil {
return nil, fmt.Errorf("Codec is required when initializing a RESTClient")
}
baseURL, versionedAPIPath, err := defaultServerUrlFor(config)
if err != nil {
return nil, err
}
transport, err := TransportFor(config)
if err != nil {
return nil, err
}
var httpClient *http.Client
if transport != http.DefaultTransport {
httpClient = &http.Client{Transport: transport}
}
versionConfig := config.ContentConfig
if versionConfig.GroupVersion == nil {
v := unversioned.SchemeGroupVersion
versionConfig.GroupVersion = &v
}
client := NewRESTClient(baseURL, versionedAPIPath, versionConfig, config.QPS, config.Burst, httpClient)
return client, nil
}
// DefaultServerURL converts a host, host:port, or URL string to the default base server API path
// to use with a Client at a given API version following the standard conventions for a
// Kubernetes API.
func DefaultServerURL(host, apiPath string, groupVersion unversioned.GroupVersion, defaultTLS bool) (*url.URL, string, error) {
if host == "" {
return nil, "", fmt.Errorf("host must be a URL or a host:port pair")
}
base := host
hostURL, err := url.Parse(base)
if err != nil {
return nil, "", err
}
if hostURL.Scheme == "" {
scheme := "http://"
if defaultTLS {
scheme = "https://"
}
hostURL, err = url.Parse(scheme + base)
if err != nil {
return nil, "", err
}
if hostURL.Path != "" && hostURL.Path != "/" {
return nil, "", fmt.Errorf("host must be a URL or a host:port pair: %q", base)
}
}
// hostURL.Path is optional; a non-empty Path is treated as a prefix that is to be applied to
// all URIs used to access the host. this is useful when there's a proxy in front of the
// apiserver that has relocated the apiserver endpoints, forwarding all requests from, for
// example, /a/b/c to the apiserver. in this case the Path should be /a/b/c.
//
// if running without a frontend proxy (that changes the location of the apiserver), then
// hostURL.Path should be blank.
//
// versionedAPIPath, a path relative to baseURL.Path, points to a versioned API base
versionedAPIPath := path.Join("/", apiPath)
// Add the version to the end of the path
if len(groupVersion.Group) > 0 {
versionedAPIPath = path.Join(versionedAPIPath, groupVersion.Group, groupVersion.Version)
} else {
versionedAPIPath = path.Join(versionedAPIPath, groupVersion.Version)
}
return hostURL, versionedAPIPath, nil
}
// IsConfigTransportTLS returns true if and only if the provided config will result in a protected
// connection to the server when it is passed to client.New() or client.RESTClientFor().
// Use to determine when to send credentials over the wire.
//
// Note: the Insecure flag is ignored when testing for this value, so MITM attacks are
// still possible.
func IsConfigTransportTLS(config Config) bool {
// determination of TLS transport does not logically require a version to be specified
// modify the copy of the config we got to satisfy preconditions for defaultServerUrlFor
config.GroupVersion = defaultVersionFor(&config)
baseURL, _, err := defaultServerUrlFor(&config)
if err != nil {
return false
}
return baseURL.Scheme == "https"
}
// defaultServerUrlFor is shared between IsConfigTransportTLS and RESTClientFor. It
// requires Host and Version to be set prior to being called.
func defaultServerUrlFor(config *Config) (*url.URL, string, error) {
// TODO: move the default to secure when the apiserver supports TLS by default
// config.Insecure is taken to mean "I want HTTPS but don't bother checking the certs against a CA."
hasCA := len(config.CAFile) != 0 || len(config.CAData) != 0
hasCert := len(config.CertFile) != 0 || len(config.CertData) != 0
defaultTLS := hasCA || hasCert || config.Insecure
host := config.Host
if host == "" {
host = "localhost"
}
if config.GroupVersion != nil {
return DefaultServerURL(host, config.APIPath, *config.GroupVersion, defaultTLS)
}
return DefaultServerURL(host, config.APIPath, unversioned.GroupVersion{}, defaultTLS)
}
// defaultVersionFor is shared between IsConfigTransportTLS and RESTClientFor
func defaultVersionFor(config *Config) *unversioned.GroupVersion {
if config.GroupVersion == nil {
// Clients default to the preferred code API version
// TODO: implement version negotiation (highest version supported by server)
// TODO this drops out when groupmeta is refactored
copyGroupVersion := registered.GroupOrDie(api.GroupName).GroupVersion
return &copyGroupVersion
}
return config.GroupVersion
}
// DefaultKubernetesUserAgent returns the default user agent that clients can use.
func DefaultKubernetesUserAgent() string {
commit := version.Get().GitCommit
if len(commit) > 7 {
commit = commit[:7]
}
if len(commit) == 0 {
commit = "unknown"
}
version := version.Get().GitVersion
seg := strings.SplitN(version, "-", 2)
version = seg[0]
return fmt.Sprintf("%s/%s (%s/%s) kubernetes/%s", path.Base(os.Args[0]), version, gruntime.GOOS, gruntime.GOARCH, commit)
}
// LoadTLSFiles copies the data from the CertFile, KeyFile, and CAFile fields into the CertData,
// KeyData, and CAFile fields, or returns an error. If no error is returned, all three fields are
// either populated or were empty to start.
func LoadTLSFiles(c *Config) error {
var err error
c.CAData, err = dataFromSliceOrFile(c.CAData, c.CAFile)
if err != nil {
return err
}
c.CertData, err = dataFromSliceOrFile(c.CertData, c.CertFile)
if err != nil {
return err
}
c.KeyData, err = dataFromSliceOrFile(c.KeyData, c.KeyFile)
if err != nil {
return err
}
return nil
}
// dataFromSliceOrFile returns data from the slice (if non-empty), or from the file,
// or an error if an error occurred reading the file
func dataFromSliceOrFile(data []byte, file string) ([]byte, error) {
if len(data) > 0 {
return data, nil
}
if len(file) > 0 {
fileData, err := ioutil.ReadFile(file)
if err != nil {
return []byte{}, err
}
return fileData, nil
}
return nil, nil
}
func AddUserAgent(config *Config, userAgent string) *Config {
fullUserAgent := DefaultKubernetesUserAgent() + "/" + userAgent
config.UserAgent = fullUserAgent
return config
return restclient.SetKubernetesDefaults(config)
}

View file

@ -1,126 +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_test
import (
"bytes"
"encoding/json"
"errors"
"io"
"io/ioutil"
"net/http"
"strings"
"testing"
"k8s.io/kubernetes/pkg/api/testapi"
uapi "k8s.io/kubernetes/pkg/api/unversioned"
unversionedapi "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/fake"
)
func objBody(object interface{}) io.ReadCloser {
output, err := json.MarshalIndent(object, "", "")
if err != nil {
panic(err)
}
return ioutil.NopCloser(bytes.NewReader([]byte(output)))
}
func TestNegotiateVersion(t *testing.T) {
tests := []struct {
name string
version *uapi.GroupVersion
expectedVersion *uapi.GroupVersion
serverVersions []string
clientVersions []uapi.GroupVersion
config *unversioned.Config
expectErr func(err error) bool
sendErr error
}{
{
name: "server supports client default",
version: &uapi.GroupVersion{Version: "version1"},
config: &unversioned.Config{},
serverVersions: []string{"version1", testapi.Default.GroupVersion().String()},
clientVersions: []uapi.GroupVersion{{Version: "version1"}, *testapi.Default.GroupVersion()},
expectedVersion: &uapi.GroupVersion{Version: "version1"},
},
{
name: "server falls back to client supported",
version: testapi.Default.GroupVersion(),
config: &unversioned.Config{},
serverVersions: []string{"version1"},
clientVersions: []uapi.GroupVersion{{Version: "version1"}, *testapi.Default.GroupVersion()},
expectedVersion: &uapi.GroupVersion{Version: "version1"},
},
{
name: "explicit version supported",
config: &unversioned.Config{ContentConfig: unversioned.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}},
serverVersions: []string{"/version1", testapi.Default.GroupVersion().String()},
clientVersions: []uapi.GroupVersion{{Version: "version1"}, *testapi.Default.GroupVersion()},
expectedVersion: testapi.Default.GroupVersion(),
},
{
name: "explicit version not supported",
config: &unversioned.Config{ContentConfig: unversioned.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}},
serverVersions: []string{"version1"},
clientVersions: []uapi.GroupVersion{{Version: "version1"}, *testapi.Default.GroupVersion()},
expectErr: func(err error) bool { return strings.Contains(err.Error(), `server does not support API version "v1"`) },
},
{
name: "connection refused error",
config: &unversioned.Config{ContentConfig: unversioned.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}},
serverVersions: []string{"version1"},
clientVersions: []uapi.GroupVersion{{Version: "version1"}, *testapi.Default.GroupVersion()},
sendErr: errors.New("connection refused"),
expectErr: func(err error) bool { return strings.Contains(err.Error(), "connection refused") },
},
}
codec := testapi.Default.Codec()
for _, test := range tests {
fakeClient := &fake.RESTClient{
Codec: codec,
Resp: &http.Response{
StatusCode: 200,
Body: objBody(&unversionedapi.APIVersions{Versions: test.serverVersions}),
},
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
if test.sendErr != nil {
return nil, test.sendErr
}
return &http.Response{StatusCode: 200, Body: objBody(&unversionedapi.APIVersions{Versions: test.serverVersions})}, nil
}),
}
c := unversioned.NewOrDie(test.config)
c.DiscoveryClient.Client = fakeClient.Client
response, err := unversioned.NegotiateVersion(c, test.config, test.version, test.clientVersions)
if err == nil && test.expectErr != nil {
t.Errorf("expected error, got nil for [%s].", test.name)
}
if err != nil {
if test.expectErr == nil || !test.expectErr(err) {
t.Errorf("unexpected error for [%s]: %v.", test.name, err)
}
continue
}
if *response != *test.expectedVersion {
t.Errorf("%s: expected version %s, got %s.", test.name, test.expectedVersion, response)
}
}
}

View file

@ -1,280 +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"
"net/http"
"net/http/httptest"
"path"
"reflect"
"strings"
"testing"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
)
func TestIsConfigTransportTLS(t *testing.T) {
testCases := []struct {
Config *Config
TransportTLS bool
}{
{
Config: &Config{},
TransportTLS: false,
},
{
Config: &Config{
Host: "https://localhost",
},
TransportTLS: true,
},
{
Config: &Config{
Host: "localhost",
TLSClientConfig: TLSClientConfig{
CertFile: "foo",
},
},
TransportTLS: true,
},
{
Config: &Config{
Host: "///:://localhost",
TLSClientConfig: TLSClientConfig{
CertFile: "foo",
},
},
TransportTLS: false,
},
{
Config: &Config{
Host: "1.2.3.4:567",
Insecure: true,
},
TransportTLS: true,
},
}
for _, testCase := range testCases {
if err := SetKubernetesDefaults(testCase.Config); err != nil {
t.Errorf("setting defaults failed for %#v: %v", testCase.Config, err)
continue
}
useTLS := IsConfigTransportTLS(*testCase.Config)
if testCase.TransportTLS != useTLS {
t.Errorf("expected %v for %#v", testCase.TransportTLS, testCase.Config)
}
}
}
func TestSetKubernetesDefaults(t *testing.T) {
testCases := []struct {
Config Config
After Config
Err bool
}{
{
Config{},
Config{
APIPath: "/api",
ContentConfig: ContentConfig{
GroupVersion: testapi.Default.GroupVersion(),
Codec: testapi.Default.Codec(),
},
QPS: 5,
Burst: 10,
},
false,
},
// Add this test back when we fixed config and SetKubernetesDefaults
// {
// Config{
// GroupVersion: &unversioned.GroupVersion{Group: "not.a.group", Version: "not_an_api"},
// },
// Config{},
// true,
// },
}
for _, testCase := range testCases {
val := &testCase.Config
err := SetKubernetesDefaults(val)
val.UserAgent = ""
switch {
case err == nil && testCase.Err:
t.Errorf("expected error but was nil")
continue
case err != nil && !testCase.Err:
t.Errorf("unexpected error %v", err)
continue
case err != nil:
continue
}
if !reflect.DeepEqual(*val, testCase.After) {
t.Errorf("unexpected result object: %#v", val)
}
}
}
func TestSetKubernetesDefaultsUserAgent(t *testing.T) {
config := &Config{}
if err := SetKubernetesDefaults(config); err != nil {
t.Errorf("unexpected error: %v", err)
}
if !strings.Contains(config.UserAgent, "kubernetes/") {
t.Errorf("no user agent set: %#v", config)
}
}
func TestHelperGetServerAPIVersions(t *testing.T) {
expect := []string{"v1", "v2", "v3"}
APIVersions := unversioned.APIVersions{Versions: expect}
expect = append(expect, "group1/v1", "group1/v2", "group2/v1", "group2/v2")
APIGroupList := unversioned.APIGroupList{
Groups: []unversioned.APIGroup{
{
Versions: []unversioned.GroupVersionForDiscovery{
{
GroupVersion: "group1/v1",
},
{
GroupVersion: "group1/v2",
},
},
},
{
Versions: []unversioned.GroupVersionForDiscovery{
{
GroupVersion: "group2/v1",
},
{
GroupVersion: "group2/v2",
},
},
},
},
}
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var output []byte
var err error
switch req.URL.Path {
case "/api":
output, err = json.Marshal(APIVersions)
case "/apis":
output, err = json.Marshal(APIGroupList)
}
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}))
// TODO: Uncomment when fix #19254
// defer server.Close()
got, err := ServerAPIVersions(&Config{Host: server.URL, ContentConfig: ContentConfig{GroupVersion: &unversioned.GroupVersion{Group: "invalid version", Version: "one"}, Codec: testapi.Default.Codec()}})
if err != nil {
t.Fatalf("unexpected encoding error: %v", err)
}
if e, a := expect, got; !reflect.DeepEqual(e, a) {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestSetsCodec(t *testing.T) {
testCases := map[string]struct {
Err bool
Prefix string
Codec runtime.Codec
}{
testapi.Default.GroupVersion().Version: {false, "/api/" + testapi.Default.GroupVersion().Version, testapi.Default.Codec()},
// Add this test back when we fixed config and SetKubernetesDefaults
// "invalidVersion": {true, "", nil},
}
for version, expected := range testCases {
client, err := New(&Config{Host: "127.0.0.1", ContentConfig: ContentConfig{GroupVersion: &unversioned.GroupVersion{Version: version}}})
switch {
case err == nil && expected.Err:
t.Errorf("expected error but was nil")
continue
case err != nil && !expected.Err:
t.Errorf("unexpected error %v", err)
continue
case err != nil:
continue
}
if e, a := expected.Prefix, client.RESTClient.versionedAPIPath; e != a {
t.Errorf("expected %#v, got %#v", e, a)
}
if e, a := expected.Codec, client.RESTClient.contentConfig.Codec; !reflect.DeepEqual(e, a) {
t.Errorf("expected %#v, got %#v", e, a)
}
}
}
func TestRESTClientRequires(t *testing.T) {
if _, err := RESTClientFor(&Config{Host: "127.0.0.1", ContentConfig: ContentConfig{Codec: testapi.Default.Codec()}}); err == nil {
t.Errorf("unexpected non-error")
}
if _, err := RESTClientFor(&Config{Host: "127.0.0.1", ContentConfig: ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}); err == nil {
t.Errorf("unexpected non-error")
}
if _, err := RESTClientFor(&Config{Host: "127.0.0.1", ContentConfig: ContentConfig{GroupVersion: testapi.Default.GroupVersion(), Codec: testapi.Default.Codec()}}); err != nil {
t.Errorf("unexpected error: %v", err)
}
}
func TestValidatesHostParameter(t *testing.T) {
testCases := []struct {
Host string
APIPath string
URL string
Err bool
}{
{"127.0.0.1", "", "http://127.0.0.1/" + testapi.Default.GroupVersion().Version, false},
{"127.0.0.1:8080", "", "http://127.0.0.1:8080/" + testapi.Default.GroupVersion().Version, false},
{"foo.bar.com", "", "http://foo.bar.com/" + testapi.Default.GroupVersion().Version, false},
{"http://host/prefix", "", "http://host/prefix/" + testapi.Default.GroupVersion().Version, false},
{"http://host", "", "http://host/" + testapi.Default.GroupVersion().Version, false},
{"http://host", "/", "http://host/" + testapi.Default.GroupVersion().Version, false},
{"http://host", "/other", "http://host/other/" + testapi.Default.GroupVersion().Version, false},
{"host/server", "", "", true},
}
for i, testCase := range testCases {
u, versionedAPIPath, err := DefaultServerURL(testCase.Host, testCase.APIPath, *testapi.Default.GroupVersion(), false)
switch {
case err == nil && testCase.Err:
t.Errorf("expected error but was nil")
continue
case err != nil && !testCase.Err:
t.Errorf("unexpected error %v", err)
continue
case err != nil:
continue
}
u.Path = path.Join(u.Path, versionedAPIPath)
if e, a := testCase.URL, u.String(); e != a {
t.Errorf("%d: expected host %s, got %s", i, e, a)
continue
}
}
}

View file

@ -1,225 +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_test
import (
. "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/testclient/simple"
)
import (
"net/url"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/apis/extensions"
)
func getHorizontalPodAutoscalersResoureName() string {
return "horizontalpodautoscalers"
}
func getClient(t *testing.T, c *simple.Client, ns, resourceGroup string) HorizontalPodAutoscalerInterface {
switch resourceGroup {
case autoscaling.GroupName:
return c.Setup(t).Autoscaling().HorizontalPodAutoscalers(ns)
case extensions.GroupName:
return c.Setup(t).Extensions().HorizontalPodAutoscalers(ns)
default:
t.Fatalf("Unknown group %v", resourceGroup)
}
return nil
}
func testHorizontalPodAutoscalerCreate(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault
horizontalPodAutoscaler := extensions.HorizontalPodAutoscaler{
ObjectMeta: api.ObjectMeta{
Name: "abc",
Namespace: ns,
},
}
c := &simple.Client{
Request: simple.Request{
Method: "POST",
Path: group.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, ""),
Query: simple.BuildQueryValues(nil),
Body: &horizontalPodAutoscaler,
},
Response: simple.Response{StatusCode: 200, Body: &horizontalPodAutoscaler},
ResourceGroup: resourceGroup,
}
response, err := getClient(t, c, ns, resourceGroup).Create(&horizontalPodAutoscaler)
defer c.Close()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
c.Validate(t, response, err)
}
func TestHorizontalPodAutoscalerCreate(t *testing.T) {
testHorizontalPodAutoscalerCreate(t, testapi.Extensions, extensions.GroupName)
testHorizontalPodAutoscalerCreate(t, testapi.Autoscaling, autoscaling.GroupName)
}
func testHorizontalPodAutoscalerGet(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault
horizontalPodAutoscaler := &extensions.HorizontalPodAutoscaler{
ObjectMeta: api.ObjectMeta{
Name: "abc",
Namespace: ns,
},
}
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: group.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, "abc"),
Query: simple.BuildQueryValues(nil),
Body: nil,
},
Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscaler},
ResourceGroup: resourceGroup,
}
response, err := getClient(t, c, ns, resourceGroup).Get("abc")
defer c.Close()
c.Validate(t, response, err)
}
func TestHorizontalPodAutoscalerGet(t *testing.T) {
testHorizontalPodAutoscalerGet(t, testapi.Extensions, extensions.GroupName)
testHorizontalPodAutoscalerGet(t, testapi.Autoscaling, autoscaling.GroupName)
}
func testHorizontalPodAutoscalerList(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault
horizontalPodAutoscalerList := &extensions.HorizontalPodAutoscalerList{
Items: []extensions.HorizontalPodAutoscaler{
{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: ns,
},
},
},
}
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: group.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, ""),
Query: simple.BuildQueryValues(nil),
Body: nil,
},
Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscalerList},
ResourceGroup: resourceGroup,
}
response, err := getClient(t, c, ns, resourceGroup).List(api.ListOptions{})
defer c.Close()
c.Validate(t, response, err)
}
func TestHorizontalPodAutoscalerList(t *testing.T) {
testHorizontalPodAutoscalerList(t, testapi.Extensions, extensions.GroupName)
testHorizontalPodAutoscalerList(t, testapi.Autoscaling, autoscaling.GroupName)
}
func testHorizontalPodAutoscalerUpdate(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault
horizontalPodAutoscaler := &extensions.HorizontalPodAutoscaler{
ObjectMeta: api.ObjectMeta{
Name: "abc",
Namespace: ns,
ResourceVersion: "1",
},
}
c := &simple.Client{
Request: simple.Request{Method: "PUT", Path: group.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, "abc"), Query: simple.BuildQueryValues(nil)},
Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscaler},
ResourceGroup: resourceGroup,
}
response, err := getClient(t, c, ns, resourceGroup).Update(horizontalPodAutoscaler)
defer c.Close()
c.Validate(t, response, err)
}
func TestHorizontalPodAutoscalerUpdate(t *testing.T) {
testHorizontalPodAutoscalerUpdate(t, testapi.Extensions, extensions.GroupName)
testHorizontalPodAutoscalerUpdate(t, testapi.Autoscaling, autoscaling.GroupName)
}
func testHorizontalPodAutoscalerUpdateStatus(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault
horizontalPodAutoscaler := &extensions.HorizontalPodAutoscaler{
ObjectMeta: api.ObjectMeta{
Name: "abc",
Namespace: ns,
ResourceVersion: "1",
},
}
c := &simple.Client{
Request: simple.Request{Method: "PUT", Path: group.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, "abc") + "/status", Query: simple.BuildQueryValues(nil)},
Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscaler},
ResourceGroup: resourceGroup,
}
response, err := getClient(t, c, ns, resourceGroup).UpdateStatus(horizontalPodAutoscaler)
defer c.Close()
c.Validate(t, response, err)
}
func TestHorizontalPodAutoscalerUpdateStatus(t *testing.T) {
testHorizontalPodAutoscalerUpdateStatus(t, testapi.Extensions, extensions.GroupName)
testHorizontalPodAutoscalerUpdateStatus(t, testapi.Autoscaling, autoscaling.GroupName)
}
func testHorizontalPodAutoscalerDelete(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault
c := &simple.Client{
Request: simple.Request{Method: "DELETE", Path: group.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, "foo"), Query: simple.BuildQueryValues(nil)},
Response: simple.Response{StatusCode: 200},
ResourceGroup: resourceGroup,
}
err := getClient(t, c, ns, resourceGroup).Delete("foo", nil)
defer c.Close()
c.Validate(t, nil, err)
}
func TestHorizontalPodAutoscalerDelete(t *testing.T) {
testHorizontalPodAutoscalerDelete(t, testapi.Extensions, extensions.GroupName)
testHorizontalPodAutoscalerDelete(t, testapi.Autoscaling, autoscaling.GroupName)
}
func testHorizontalPodAutoscalerWatch(t *testing.T, group testapi.TestGroup, resourceGroup string) {
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: group.ResourcePathWithPrefix("watch", getHorizontalPodAutoscalersResoureName(), "", ""),
Query: url.Values{"resourceVersion": []string{}}},
Response: simple.Response{StatusCode: 200},
ResourceGroup: resourceGroup,
}
_, err := getClient(t, c, api.NamespaceAll, resourceGroup).Watch(api.ListOptions{})
defer c.Close()
c.Validate(t, nil, err)
}
func TestHorizontalPodAutoscalerWatch(t *testing.T) {
testHorizontalPodAutoscalerWatch(t, testapi.Extensions, extensions.GroupName)
testHorizontalPodAutoscalerWatch(t, testapi.Autoscaling, autoscaling.GroupName)
}

View file

@ -24,6 +24,7 @@ import (
"k8s.io/kubernetes/pkg/apimachinery/registered"
_ "k8s.io/kubernetes/pkg/apis/authorization/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"

View file

@ -1,240 +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_test
import (
. "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/testclient/simple"
)
import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/apis/extensions"
)
func getIngressResourceName() string {
return "ingresses"
}
func TestListIngress(t *testing.T) {
ns := api.NamespaceAll
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: testapi.Extensions.ResourcePath(getIngressResourceName(), ns, ""),
},
Response: simple.Response{StatusCode: 200,
Body: &extensions.IngressList{
Items: []extensions.Ingress{
{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.IngressSpec{
Rules: []extensions.IngressRule{},
},
},
},
},
},
}
receivedIngressList, err := c.Setup(t).Extensions().Ingress(ns).List(api.ListOptions{})
defer c.Close()
c.Validate(t, receivedIngressList, err)
}
func TestGetIngress(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: testapi.Extensions.ResourcePath(getIngressResourceName(), ns, "foo"),
Query: simple.BuildQueryValues(nil),
},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.Ingress{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.IngressSpec{
Rules: []extensions.IngressRule{},
},
},
},
}
receivedIngress, err := c.Setup(t).Extensions().Ingress(ns).Get("foo")
defer c.Close()
c.Validate(t, receivedIngress, err)
}
func TestGetIngressWithNoName(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{Error: true}
receivedIngress, err := c.Setup(t).Extensions().Ingress(ns).Get("")
defer c.Close()
if (err != nil) && (err.Error() != simple.NameRequiredError) {
t.Errorf("Expected error: %v, but got %v", simple.NameRequiredError, err)
}
c.Validate(t, receivedIngress, err)
}
func TestUpdateIngress(t *testing.T) {
ns := api.NamespaceDefault
requestIngress := &extensions.Ingress{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: ns,
ResourceVersion: "1",
},
}
c := &simple.Client{
Request: simple.Request{
Method: "PUT",
Path: testapi.Extensions.ResourcePath(getIngressResourceName(), ns, "foo"),
Query: simple.BuildQueryValues(nil),
},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.Ingress{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.IngressSpec{
Rules: []extensions.IngressRule{},
},
},
},
}
receivedIngress, err := c.Setup(t).Extensions().Ingress(ns).Update(requestIngress)
defer c.Close()
c.Validate(t, receivedIngress, err)
}
func TestUpdateIngressStatus(t *testing.T) {
ns := api.NamespaceDefault
lbStatus := api.LoadBalancerStatus{
Ingress: []api.LoadBalancerIngress{
{IP: "127.0.0.1"},
},
}
requestIngress := &extensions.Ingress{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: ns,
ResourceVersion: "1",
},
Status: extensions.IngressStatus{
LoadBalancer: lbStatus,
},
}
c := &simple.Client{
Request: simple.Request{
Method: "PUT",
Path: testapi.Extensions.ResourcePath(getIngressResourceName(), ns, "foo") + "/status",
Query: simple.BuildQueryValues(nil),
},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.Ingress{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.IngressSpec{
Rules: []extensions.IngressRule{},
},
Status: extensions.IngressStatus{
LoadBalancer: lbStatus,
},
},
},
}
receivedIngress, err := c.Setup(t).Extensions().Ingress(ns).UpdateStatus(requestIngress)
defer c.Close()
c.Validate(t, receivedIngress, err)
}
func TestDeleteIngress(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{
Request: simple.Request{
Method: "DELETE",
Path: testapi.Extensions.ResourcePath(getIngressResourceName(), ns, "foo"),
Query: simple.BuildQueryValues(nil),
},
Response: simple.Response{StatusCode: 200},
}
err := c.Setup(t).Extensions().Ingress(ns).Delete("foo", nil)
defer c.Close()
c.Validate(t, nil, err)
}
func TestCreateIngress(t *testing.T) {
ns := api.NamespaceDefault
requestIngress := &extensions.Ingress{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: ns,
},
}
c := &simple.Client{
Request: simple.Request{
Method: "POST",
Path: testapi.Extensions.ResourcePath(getIngressResourceName(), ns, ""),
Body: requestIngress,
Query: simple.BuildQueryValues(nil),
},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.Ingress{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.IngressSpec{
Rules: []extensions.IngressRule{},
},
},
},
}
receivedIngress, err := c.Setup(t).Extensions().Ingress(ns).Create(requestIngress)
defer c.Close()
c.Validate(t, receivedIngress, err)
}

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