ref(*): kubernetes v1.10 support

parent 19c73207
This diff is collapsed.
...@@ -43,28 +43,20 @@ import: ...@@ -43,28 +43,20 @@ import:
- package: github.com/evanphx/json-patch - package: github.com/evanphx/json-patch
- package: github.com/BurntSushi/toml - package: github.com/BurntSushi/toml
version: ~0.3.0 version: ~0.3.0
- package: github.com/naoina/go-stringutil
version: ~0.1.0
- package: github.com/chai2010/gettext-go
- package: github.com/prometheus/client_golang - package: github.com/prometheus/client_golang
version: 0.8.0 version: 0.8.0
- package: vbom.ml/util - package: github.com/grpc-ecosystem/go-grpc-prometheus
repo: https://github.com/fvbommel/util.git
vcs: git
- package: k8s.io/kubernetes - package: k8s.io/kubernetes
version: 1.9.2 version: release-1.10
- package: k8s.io/client-go - package: k8s.io/client-go
version: ~6.0.0 version: kubernetes-1.10.0
- package: k8s.io/api - package: k8s.io/api
version: kubernetes-1.9.2 version: release-1.10
- package: k8s.io/apimachinery - package: k8s.io/apimachinery
version: kubernetes-1.9.2 version: release-1.10
- package: k8s.io/apiserver - package: k8s.io/apiserver
version: kubernetes-1.9.2 version: release-1.10
- package: cloud.google.com/go/compute
repo: https://github.com/GoogleCloudPlatform/google-cloud-go.git
testImports: testImports:
- package: github.com/stretchr/testify - package: github.com/stretchr/testify
......
...@@ -47,7 +47,7 @@ import ( ...@@ -47,7 +47,7 @@ import (
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
batchinternal "k8s.io/kubernetes/pkg/apis/batch" batchinternal "k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/core"
conditions "k8s.io/kubernetes/pkg/client/unversioned" "k8s.io/kubernetes/pkg/client/conditions"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
...@@ -77,10 +77,12 @@ func New(config clientcmd.ClientConfig) *Client { ...@@ -77,10 +77,12 @@ func New(config clientcmd.ClientConfig) *Client {
return &Client{ return &Client{
Factory: cmdutil.NewFactory(config), Factory: cmdutil.NewFactory(config),
SchemaCacheDir: clientcmd.RecommendedSchemaFile, SchemaCacheDir: clientcmd.RecommendedSchemaFile,
Log: func(_ string, _ ...interface{}) {}, Log: nopLogger,
} }
} }
var nopLogger = func(_ string, _ ...interface{}) {}
// ResourceActorFunc performs an action on a single resource. // ResourceActorFunc performs an action on a single resource.
type ResourceActorFunc func(*resource.Info) error type ResourceActorFunc func(*resource.Info) error
...@@ -205,7 +207,10 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) { ...@@ -205,7 +207,10 @@ func (c *Client) Get(namespace string, reader io.Reader) (string, error) {
// an object type changes, so we can just rely on that. Problem is it doesn't seem to keep // an object type changes, so we can just rely on that. Problem is it doesn't seem to keep
// track of tab widths. // track of tab widths.
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
p, _ := c.Printer(nil, printers.PrintOptions{}) p, err := cmdutil.PrinterForOptions(&printers.PrintOptions{})
if err != nil {
return "", err
}
for t, ot := range objs { for t, ot := range objs {
if _, err = buf.WriteString("==> " + t + "\n"); err != nil { if _, err = buf.WriteString("==> " + t + "\n"); err != nil {
return "", err return "", err
...@@ -608,7 +613,8 @@ func (c *Client) AsVersionedObject(obj runtime.Object) (runtime.Object, error) { ...@@ -608,7 +613,8 @@ func (c *Client) AsVersionedObject(obj runtime.Object) (runtime.Object, error) {
return nil, err return nil, err
} }
versions := &runtime.VersionedObjects{} versions := &runtime.VersionedObjects{}
err = runtime.DecodeInto(c.Decoder(true), json, versions) decoder := unstructured.UnstructuredJSONScheme
err = runtime.DecodeInto(decoder, json, versions)
return versions.First(), err return versions.First(), err
} }
......
...@@ -18,8 +18,6 @@ package kube ...@@ -18,8 +18,6 @@ package kube
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
...@@ -31,19 +29,20 @@ import ( ...@@ -31,19 +29,20 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/kubectl/scheme"
watchjson "k8s.io/kubernetes/pkg/watch/json"
) )
var unstructuredSerializer = dynamic.ContentConfig().NegotiatedSerializer
func objBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser { func objBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser {
return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj)))) return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj))))
} }
...@@ -117,31 +116,21 @@ func (f *fakeReaperFactory) Reaper(mapping *meta.RESTMapping) (kubectl.Reaper, e ...@@ -117,31 +116,21 @@ func (f *fakeReaperFactory) Reaper(mapping *meta.RESTMapping) (kubectl.Reaper, e
return f.reaper, nil return f.reaper, nil
} }
func newEventResponse(code int, e *watch.Event) (*http.Response, error) { type testClient struct {
dispatchedEvent, err := encodeAndMarshalEvent(e) *Client
if err != nil { *cmdtesting.TestFactory
return nil, err
}
header := http.Header{}
header.Set("Content-Type", runtime.ContentTypeJSON)
body := ioutil.NopCloser(bytes.NewReader(dispatchedEvent))
return &http.Response{StatusCode: code, Header: header, Body: body}, nil
} }
func encodeAndMarshalEvent(e *watch.Event) ([]byte, error) { func newTestClient() *testClient {
encodedEvent, err := watchjson.Object(testapi.Default.Codec(), e) tf := cmdtesting.NewTestFactory()
if err != nil { c := &Client{
return nil, err Factory: tf,
Log: nopLogger,
}
return &testClient{
Client: c,
TestFactory: tf,
} }
return json.Marshal(encodedEvent)
}
func newTestClient(f cmdutil.Factory) *Client {
c := New(nil)
c.Factory = f
return c
} }
func TestUpdate(t *testing.T) { func TestUpdate(t *testing.T) {
...@@ -153,10 +142,11 @@ func TestUpdate(t *testing.T) { ...@@ -153,10 +142,11 @@ func TestUpdate(t *testing.T) {
var actions []string var actions []string
f, tf, codec, _ := cmdtesting.NewAPIFactory() tf := cmdtesting.NewTestFactory()
defer tf.Cleanup()
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"}, GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: dynamic.ContentConfig().NegotiatedSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
p, m := req.URL.Path, req.Method p, m := req.URL.Path, req.Method
actions = append(actions, p+":"+m) actions = append(actions, p+":"+m)
...@@ -190,9 +180,11 @@ func TestUpdate(t *testing.T) { ...@@ -190,9 +180,11 @@ func TestUpdate(t *testing.T) {
}), }),
} }
c := newTestClient()
reaper := &fakeReaper{} reaper := &fakeReaper{}
rf := &fakeReaperFactory{Factory: f, reaper: reaper} rf := &fakeReaperFactory{Factory: tf, reaper: reaper}
c := newTestClient(rf) c.Client.Factory = rf
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
if err := c.Update(core.NamespaceDefault, objBody(codec, &listA), objBody(codec, &listB), false, false, 0, false); err != nil { if err := c.Update(core.NamespaceDefault, objBody(codec, &listA), objBody(codec, &listB), false, false, 0, false); err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -251,54 +243,35 @@ func TestBuild(t *testing.T) { ...@@ -251,54 +243,35 @@ func TestBuild(t *testing.T) {
}, },
} }
c := newTestClient()
for _, tt := range tests { for _, tt := range tests {
f, _, _, _ := cmdtesting.NewAPIFactory() t.Run(tt.name, func(t *testing.T) {
c := newTestClient(f) c.Cleanup()
// Test for an invalid manifest // Test for an invalid manifest
infos, err := c.Build(tt.namespace, tt.reader) infos, err := c.Build(tt.namespace, tt.reader)
if err != nil && !tt.err { if err != nil && !tt.err {
t.Errorf("%q. Got error message when no error should have occurred: %v", tt.name, err) t.Errorf("Got error message when no error should have occurred: %v", err)
} else if err != nil && strings.Contains(err.Error(), "--validate=false") { } else if err != nil && strings.Contains(err.Error(), "--validate=false") {
t.Errorf("%q. error message was not scrubbed", tt.name) t.Error("error message was not scrubbed")
} }
if len(infos) != tt.count { if len(infos) != tt.count {
t.Errorf("%q. expected %d result objects, got %d", tt.name, tt.count, len(infos)) t.Errorf("expected %d result objects, got %d", tt.count, len(infos))
} }
})
} }
} }
type testPrinter struct {
Objects []runtime.Object
Err error
printers.ResourcePrinter
}
func (t *testPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
t.Objects = append(t.Objects, obj)
fmt.Fprintf(out, "%#v", obj)
return t.Err
}
func (t *testPrinter) HandledResources() []string {
return []string{}
}
func (t *testPrinter) AfterPrint(io.Writer, string) error {
return t.Err
}
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
list := newPodList("starfish", "otter") list := newPodList("starfish", "otter")
f, tf, _, _ := cmdtesting.NewAPIFactory() c := newTestClient()
tf.Printer = &testPrinter{} defer c.Cleanup()
tf.UnstructuredClient = &fake.RESTClient{ c.TestFactory.UnstructuredClient = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"}, GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: dynamic.ContentConfig().NegotiatedSerializer, NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
p, m := req.URL.Path, req.Method p, m := req.URL.Path, req.Method
//actions = append(actions, p+":"+m)
t.Logf("got request %s %s", p, m) t.Logf("got request %s %s", p, m)
switch { switch {
case p == "/namespaces/default/pods/starfish" && m == "GET": case p == "/namespaces/default/pods/starfish" && m == "GET":
...@@ -311,7 +284,6 @@ func TestGet(t *testing.T) { ...@@ -311,7 +284,6 @@ func TestGet(t *testing.T) {
} }
}), }),
} }
c := newTestClient(f)
// Test Success // Test Success
data := strings.NewReader("kind: Pod\napiVersion: v1\nmetadata:\n name: otter") data := strings.NewReader("kind: Pod\napiVersion: v1\nmetadata:\n name: otter")
...@@ -358,101 +330,37 @@ func TestPerform(t *testing.T) { ...@@ -358,101 +330,37 @@ func TestPerform(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
results := []*resource.Info{} t.Run(tt.name, func(t *testing.T) {
results := []*resource.Info{}
fn := func(info *resource.Info) error { fn := func(info *resource.Info) error {
results = append(results, info) results = append(results, info)
if info.Namespace != tt.namespace { if info.Namespace != tt.namespace {
t.Errorf("%q. expected namespace to be '%s', got %s", tt.name, tt.namespace, info.Namespace) t.Errorf("expected namespace to be '%s', got %s", tt.namespace, info.Namespace)
}
return nil
} }
return nil
}
f, _, _, _ := cmdtesting.NewAPIFactory() c := newTestClient()
c := newTestClient(f) defer c.Cleanup()
infos, err := c.Build(tt.namespace, tt.reader) infos, err := c.Build(tt.namespace, tt.reader)
if err != nil && err.Error() != tt.errMessage { if err != nil && err.Error() != tt.errMessage {
t.Errorf("%q. Error while building manifests: %v", tt.name, err) t.Errorf("Error while building manifests: %v", err)
} }
err = perform(infos, fn)
if (err != nil) != tt.err {
t.Errorf("%q. expected error: %v, got %v", tt.name, tt.err, err)
}
if err != nil && err.Error() != tt.errMessage {
t.Errorf("%q. expected error message: %v, got %v", tt.name, tt.errMessage, err)
}
if len(results) != tt.count {
t.Errorf("%q. expected %d result objects, got %d", tt.name, tt.count, len(results))
}
}
}
func TestWaitAndGetCompletedPodPhase(t *testing.T) {
tests := []struct {
podPhase core.PodPhase
expectedPhase core.PodPhase
err bool
errMessage string
}{
{
podPhase: core.PodPending,
expectedPhase: core.PodUnknown,
err: true,
errMessage: "watch closed before Until timeout",
}, {
podPhase: core.PodRunning,
expectedPhase: core.PodUnknown,
err: true,
errMessage: "watch closed before Until timeout",
}, {
podPhase: core.PodSucceeded,
expectedPhase: core.PodSucceeded,
}, {
podPhase: core.PodFailed,
expectedPhase: core.PodFailed,
},
}
for _, tt := range tests {
f, tf, codec, ns := cmdtesting.NewAPIFactory()
actions := make(map[string]string)
var testPodList core.PodList
testPodList.Items = append(testPodList.Items, newPodWithStatus("bestpod", core.PodStatus{Phase: tt.podPhase}, "test"))
tf.Client = &fake.RESTClient{
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
p, m := req.URL.Path, req.Method
actions[p] = m
switch {
case p == "/namespaces/test/pods/bestpod" && m == "GET":
return newResponse(200, &testPodList.Items[0])
case p == "/namespaces/test/pods" && m == "GET":
event := watch.Event{Type: watch.Added, Object: &testPodList.Items[0]}
return newEventResponse(200, &event)
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
c := newTestClient(f) err = perform(infos, fn)
if (err != nil) != tt.err {
t.Errorf("expected error: %v, got %v", tt.err, err)
}
if err != nil && err.Error() != tt.errMessage {
t.Errorf("expected error message: %v, got %v", tt.errMessage, err)
}
phase, err := c.WaitAndGetCompletedPodPhase("test", objBody(codec, &testPodList), 1*time.Second) if len(results) != tt.count {
if (err != nil) != tt.err { t.Errorf("expected %d result objects, got %d", tt.count, len(results))
t.Fatalf("Expected error but there was none.") }
} })
if err != nil && err.Error() != tt.errMessage {
t.Fatalf("Expected error %s, got %s", tt.errMessage, err.Error())
}
if phase != tt.expectedPhase {
t.Fatalf("Expected pod phase %s, got %s", tt.expectedPhase, phase)
}
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment