mirror of https://github.com/k3s-io/k3s
Merge pull request #196 from lavalamp/marshal
Make api able to marshal its types correctlypull/6/head
commit
49c25a4e28
|
@ -169,7 +169,7 @@ func executeAPIRequest(method string, auth *kube_client.AuthInfo) bool {
|
||||||
printer = &cloudcfg.HumanReadablePrinter{}
|
printer = &cloudcfg.HumanReadablePrinter{}
|
||||||
}
|
}
|
||||||
|
|
||||||
var body string
|
var body []byte
|
||||||
if body, err = cloudcfg.DoRequest(request, auth); err == nil {
|
if body, err = cloudcfg.DoRequest(request, auth); err == nil {
|
||||||
if err = printer.Print(body, os.Stdout); err != nil {
|
if err = printer.Print(body, os.Stdout); err != nil {
|
||||||
log.Fatalf("Failed to print: %#v\nRaw received text:\n%v\n", err, string(body))
|
log.Fatalf("Failed to print: %#v\nRaw received text:\n%v\n", err, string(body))
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
Copyright 2014 Google Inc. 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 (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"gopkg.in/v1/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
var knownTypes = map[string]reflect.Type{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
AddKnownTypes(
|
||||||
|
PodList{},
|
||||||
|
Pod{},
|
||||||
|
ReplicationControllerList{},
|
||||||
|
ReplicationController{},
|
||||||
|
ServiceList{},
|
||||||
|
Service{},
|
||||||
|
Status{},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddKnownTypes(types ...interface{}) {
|
||||||
|
for _, obj := range types {
|
||||||
|
t := reflect.TypeOf(obj)
|
||||||
|
knownTypes[t.Name()] = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode turns the given api object into an appropriate JSON string.
|
||||||
|
// Will return an error if the object doesn't have an embedded JSONBase.
|
||||||
|
// Obj may be a pointer to a struct, or a struct. If a struct, a copy
|
||||||
|
// will be made so that the object's Kind field can be set. If a pointer,
|
||||||
|
// we change the Kind field, marshal, and then set the kind field back to
|
||||||
|
// "". Having to keep track of the kind field makes tests very annoying,
|
||||||
|
// so the rule is it's set only in wire format (json), not when in native
|
||||||
|
// format.
|
||||||
|
func Encode(obj interface{}) (data []byte, err error) {
|
||||||
|
obj = checkPtr(obj)
|
||||||
|
jsonBase, err := prepareEncode(obj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data, err = json.MarshalIndent(obj, "", " ")
|
||||||
|
jsonBase.Kind = ""
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPtr(obj interface{}) interface{} {
|
||||||
|
v := reflect.ValueOf(obj)
|
||||||
|
if v.Kind() == reflect.Ptr {
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
v2 := reflect.New(v.Type())
|
||||||
|
v2.Elem().Set(v)
|
||||||
|
return v2.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareEncode(obj interface{}) (*JSONBase, error) {
|
||||||
|
name, jsonBase, err := nameAndJSONBase(obj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, contains := knownTypes[name]; !contains {
|
||||||
|
return nil, fmt.Errorf("struct %v won't be unmarshalable because it's not in knownTypes", name)
|
||||||
|
}
|
||||||
|
jsonBase.Kind = name
|
||||||
|
return jsonBase, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the name of the type (sans pointer), and its kind field. Takes pointer-to-struct..
|
||||||
|
func nameAndJSONBase(obj interface{}) (string, *JSONBase, error) {
|
||||||
|
v := reflect.ValueOf(obj)
|
||||||
|
if v.Kind() != reflect.Ptr {
|
||||||
|
return "", nil, fmt.Errorf("expected pointer, but got %v", v.Type().Name())
|
||||||
|
}
|
||||||
|
v = v.Elem()
|
||||||
|
name := v.Type().Name()
|
||||||
|
if v.Kind() != reflect.Struct {
|
||||||
|
return "", nil, fmt.Errorf("expected struct, but got %v", name)
|
||||||
|
}
|
||||||
|
jsonBase := v.FieldByName("JSONBase")
|
||||||
|
if !jsonBase.IsValid() {
|
||||||
|
return "", nil, fmt.Errorf("struct %v lacks embedded JSON type", name)
|
||||||
|
}
|
||||||
|
return name, jsonBase.Addr().Interface().(*JSONBase), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode converts a JSON string back into a pointer to an api object. Deduces the type
|
||||||
|
// based upon the Kind field (set by encode).
|
||||||
|
func Decode(data []byte) (interface{}, error) {
|
||||||
|
findKind := struct {
|
||||||
|
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||||
|
}{}
|
||||||
|
// yaml is a superset of json, so we use it to decode here. That way, we understand both.
|
||||||
|
err := yaml.Unmarshal(data, &findKind)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Couldn't get kind: %#v", err)
|
||||||
|
}
|
||||||
|
objType, found := knownTypes[findKind.Kind]
|
||||||
|
if !found {
|
||||||
|
return nil, fmt.Errorf("%v is not a known type", findKind.Kind)
|
||||||
|
}
|
||||||
|
obj := reflect.New(objType).Interface()
|
||||||
|
err = yaml.Unmarshal(data, obj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, jsonBase, err := nameAndJSONBase(obj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Don't leave these set. Track type with go's type.
|
||||||
|
jsonBase.Kind = ""
|
||||||
|
return obj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeInto parses a JSON string and stores it in obj. Returns an error
|
||||||
|
// if data.Kind is set and doesn't match the type of obj. Obj should be a
|
||||||
|
// pointer to an api type.
|
||||||
|
func DecodeInto(data []byte, obj interface{}) error {
|
||||||
|
err := yaml.Unmarshal(data, obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
name, jsonBase, err := nameAndJSONBase(obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if jsonBase.Kind != "" && jsonBase.Kind != name {
|
||||||
|
return fmt.Errorf("data had kind %v, but passed object was of type %v", jsonBase.Kind, name)
|
||||||
|
}
|
||||||
|
// Don't leave these set. Track type with go's type.
|
||||||
|
jsonBase.Kind = ""
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func runTest(t *testing.T, source interface{}) {
|
||||||
|
name := reflect.TypeOf(source).Name()
|
||||||
|
data, err := Encode(source)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v: %v", name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
obj2, err := Decode(data)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v: %v", name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(source, obj2) {
|
||||||
|
t.Errorf("%v: wanted %#v, got %#v", name, source, obj2)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface()
|
||||||
|
err = DecodeInto(data, obj3)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%v: %v", name, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(source, obj3) {
|
||||||
|
t.Errorf("%v: wanted %#v, got %#v", name, source, obj3)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTypes(t *testing.T) {
|
||||||
|
// TODO: auto-fill all fields.
|
||||||
|
table := []interface{}{
|
||||||
|
&Pod{
|
||||||
|
JSONBase: JSONBase{
|
||||||
|
ID: "mylittlepod",
|
||||||
|
},
|
||||||
|
Labels: map[string]string{
|
||||||
|
"name": "pinky",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&Service{},
|
||||||
|
&ServiceList{
|
||||||
|
Items: []Service{
|
||||||
|
{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ReplicationControllerList{},
|
||||||
|
&ReplicationController{},
|
||||||
|
&PodList{},
|
||||||
|
}
|
||||||
|
for _, item := range table {
|
||||||
|
runTest(t, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNonPtr(t *testing.T) {
|
||||||
|
obj := interface{}(Pod{Labels: map[string]string{"name": "foo"}})
|
||||||
|
data, err := Encode(obj)
|
||||||
|
obj2, err2 := Decode(data)
|
||||||
|
if err != nil || err2 != nil {
|
||||||
|
t.Errorf("Failure: %v %v", err2, err2)
|
||||||
|
}
|
||||||
|
if _, ok := obj2.(*Pod); !ok {
|
||||||
|
t.Errorf("Got wrong type")
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(obj2, &Pod{Labels: map[string]string{"name": "foo"}}) {
|
||||||
|
t.Errorf("Something changed: %#v", obj2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPtr(t *testing.T) {
|
||||||
|
obj := interface{}(&Pod{Labels: map[string]string{"name": "foo"}})
|
||||||
|
data, err := Encode(obj)
|
||||||
|
obj2, err2 := Decode(data)
|
||||||
|
if err != nil || err2 != nil {
|
||||||
|
t.Errorf("Failure: %v %v", err2, err2)
|
||||||
|
}
|
||||||
|
if _, ok := obj2.(*Pod); !ok {
|
||||||
|
t.Errorf("Got wrong type")
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(obj2, &Pod{Labels: map[string]string{"name": "foo"}}) {
|
||||||
|
t.Errorf("Something changed: %#v", obj2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test rejection of bad JSON.
|
|
@ -174,3 +174,21 @@ type Endpoints struct {
|
||||||
Name string
|
Name string
|
||||||
Endpoints []string
|
Endpoints []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Status is a return value for calls that don't return other objects.
|
||||||
|
// Arguably, this could go in apiserver, but I'm including it here so clients needn't
|
||||||
|
// import both.
|
||||||
|
type Status struct {
|
||||||
|
JSONBase `json:",inline" yaml:",inline"`
|
||||||
|
// One of: "success", "failure", "working" (for operations not yet completed)
|
||||||
|
// TODO: if "working", include an operation identifier so final status can be
|
||||||
|
// checked.
|
||||||
|
Status string `json:"status,omitempty" yaml:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values of Status.Status
|
||||||
|
const (
|
||||||
|
StatusSuccess = "success"
|
||||||
|
StatusFailure = "failure"
|
||||||
|
StatusWorking = "working"
|
||||||
|
)
|
||||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
package apiserver
|
package apiserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
@ -27,6 +26,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
)
|
)
|
||||||
|
@ -36,7 +36,7 @@ type RESTStorage interface {
|
||||||
List(labels.Selector) (interface{}, error)
|
List(labels.Selector) (interface{}, error)
|
||||||
Get(id string) (interface{}, error)
|
Get(id string) (interface{}, error)
|
||||||
Delete(id string) (<-chan interface{}, error)
|
Delete(id string) (<-chan interface{}, error)
|
||||||
Extract(body string) (interface{}, error)
|
Extract(body []byte) (interface{}, error)
|
||||||
Create(interface{}) (<-chan interface{}, error)
|
Create(interface{}) (<-chan interface{}, error)
|
||||||
Update(interface{}) (<-chan interface{}, error)
|
Update(interface{}) (<-chan interface{}, error)
|
||||||
}
|
}
|
||||||
|
@ -50,11 +50,6 @@ func MakeAsync(fn func() interface{}) <-chan interface{} {
|
||||||
return channel
|
return channel
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status is a return value for calls that don't return other objects
|
|
||||||
type Status struct {
|
|
||||||
Success bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApiServer is an HTTPHandler that delegates to RESTStorage objects.
|
// ApiServer is an HTTPHandler that delegates to RESTStorage objects.
|
||||||
// It handles URLs of the form:
|
// It handles URLs of the form:
|
||||||
// ${prefix}/${storage_key}[/${object_name}]
|
// ${prefix}/${storage_key}[/${object_name}]
|
||||||
|
@ -130,7 +125,7 @@ func (server *ApiServer) notFound(req *http.Request, w http.ResponseWriter) {
|
||||||
|
|
||||||
func (server *ApiServer) write(statusCode int, object interface{}, w http.ResponseWriter) {
|
func (server *ApiServer) write(statusCode int, object interface{}, w http.ResponseWriter) {
|
||||||
w.WriteHeader(statusCode)
|
w.WriteHeader(statusCode)
|
||||||
output, err := json.MarshalIndent(object, "", " ")
|
output, err := api.Encode(object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
server.error(err, w)
|
server.error(err, w)
|
||||||
return
|
return
|
||||||
|
@ -143,10 +138,10 @@ func (server *ApiServer) error(err error, w http.ResponseWriter) {
|
||||||
fmt.Fprintf(w, "Internal Error: %#v", err)
|
fmt.Fprintf(w, "Internal Error: %#v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *ApiServer) readBody(req *http.Request) (string, error) {
|
func (server *ApiServer) readBody(req *http.Request) ([]byte, error) {
|
||||||
defer req.Body.Close()
|
defer req.Body.Close()
|
||||||
body, err := ioutil.ReadAll(req.Body)
|
body, err := ioutil.ReadAll(req.Body)
|
||||||
return string(body), err
|
return body, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *ApiServer) waitForObject(out <-chan interface{}, timeout time.Duration) (interface{}, error) {
|
func (server *ApiServer) waitForObject(out <-chan interface{}, timeout time.Duration) (interface{}, error) {
|
||||||
|
@ -248,7 +243,7 @@ func (server *ApiServer) handleREST(parts []string, requestUrl *url.URL, req *ht
|
||||||
}
|
}
|
||||||
out, err := storage.Delete(parts[1])
|
out, err := storage.Delete(parts[1])
|
||||||
var obj interface{}
|
var obj interface{}
|
||||||
obj = Status{Success: true}
|
obj = api.Status{Status: api.StatusSuccess}
|
||||||
if err == nil && sync {
|
if err == nil && sync {
|
||||||
obj, err = server.waitForObject(out, timeout)
|
obj, err = server.waitForObject(out, timeout)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,14 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
api.AddKnownTypes(Simple{}, SimpleList{})
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: This doesn't reduce typing enough to make it worth the less readable errors. Remove.
|
// TODO: This doesn't reduce typing enough to make it worth the less readable errors. Remove.
|
||||||
func expectNoError(t *testing.T, err error) {
|
func expectNoError(t *testing.T, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -38,11 +43,13 @@ func expectNoError(t *testing.T, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Simple struct {
|
type Simple struct {
|
||||||
Name string
|
api.JSONBase `yaml:",inline" json:",inline"`
|
||||||
|
Name string `yaml:"name,omitempty" json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SimpleList struct {
|
type SimpleList struct {
|
||||||
Items []Simple
|
api.JSONBase `yaml:",inline" json:",inline"`
|
||||||
|
Items []Simple `yaml:"items,omitempty" json:"items,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SimpleRESTStorage struct {
|
type SimpleRESTStorage struct {
|
||||||
|
@ -55,7 +62,7 @@ type SimpleRESTStorage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *SimpleRESTStorage) List(labels.Selector) (interface{}, error) {
|
func (storage *SimpleRESTStorage) List(labels.Selector) (interface{}, error) {
|
||||||
result := SimpleList{
|
result := &SimpleList{
|
||||||
Items: storage.list,
|
Items: storage.list,
|
||||||
}
|
}
|
||||||
return result, storage.err
|
return result, storage.err
|
||||||
|
@ -70,9 +77,9 @@ func (storage *SimpleRESTStorage) Delete(id string) (<-chan interface{}, error)
|
||||||
return storage.channel, storage.err
|
return storage.channel, storage.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *SimpleRESTStorage) Extract(body string) (interface{}, error) {
|
func (storage *SimpleRESTStorage) Extract(body []byte) (interface{}, error) {
|
||||||
var item Simple
|
var item Simple
|
||||||
json.Unmarshal([]byte(body), &item)
|
api.DecodeInto(body, &item)
|
||||||
return item, storage.err
|
return item, storage.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +98,7 @@ func extractBody(response *http.Response, object interface{}) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return string(body), err
|
return string(body), err
|
||||||
}
|
}
|
||||||
err = json.Unmarshal(body, object)
|
err = api.DecodeInto(body, object)
|
||||||
return string(body), err
|
return string(body), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,8 +156,10 @@ func TestNonEmptyList(t *testing.T) {
|
||||||
|
|
||||||
var listOut SimpleList
|
var listOut SimpleList
|
||||||
body, err := extractBody(resp, &listOut)
|
body, err := extractBody(resp, &listOut)
|
||||||
|
expectNoError(t, err)
|
||||||
if len(listOut.Items) != 1 {
|
if len(listOut.Items) != 1 {
|
||||||
t.Errorf("Unexpected response: %#v", listOut)
|
t.Errorf("Unexpected response: %#v", listOut)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if listOut.Items[0].Name != simpleStorage.list[0].Name {
|
if listOut.Items[0].Name != simpleStorage.list[0].Name {
|
||||||
t.Errorf("Unexpected data: %#v, %s", listOut.Items[0], string(body))
|
t.Errorf("Unexpected data: %#v, %s", listOut.Items[0], string(body))
|
||||||
|
|
|
@ -113,7 +113,7 @@ func RequestWithBodyData(data []byte, url, method string) (*http.Request, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute a request, adds authentication (if auth != nil), and HTTPS cert ignoring.
|
// Execute a request, adds authentication (if auth != nil), and HTTPS cert ignoring.
|
||||||
func DoRequest(request *http.Request, auth *client.AuthInfo) (string, error) {
|
func DoRequest(request *http.Request, auth *client.AuthInfo) ([]byte, error) {
|
||||||
if auth != nil {
|
if auth != nil {
|
||||||
request.SetBasicAuth(auth.User, auth.Password)
|
request.SetBasicAuth(auth.User, auth.Password)
|
||||||
}
|
}
|
||||||
|
@ -123,11 +123,11 @@ func DoRequest(request *http.Request, auth *client.AuthInfo) (string, error) {
|
||||||
client := &http.Client{Transport: tr}
|
client := &http.Client{Transport: tr}
|
||||||
response, err := client.Do(request)
|
response, err := client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return []byte{}, err
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
body, err := ioutil.ReadAll(response.Body)
|
body, err := ioutil.ReadAll(response.Body)
|
||||||
return string(body), err
|
return body, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// StopController stops a controller named 'name' by setting replicas to zero
|
// StopController stops a controller named 'name' by setting replicas to zero
|
||||||
|
|
|
@ -164,7 +164,7 @@ func TestDoRequest(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Unexpected error")
|
t.Error("Unexpected error")
|
||||||
}
|
}
|
||||||
if body != expectedBody {
|
if string(body) != expectedBody {
|
||||||
t.Errorf("Expected body: '%s', saw: '%s'", expectedBody, body)
|
t.Errorf("Expected body: '%s', saw: '%s'", expectedBody, body)
|
||||||
}
|
}
|
||||||
fakeHandler.ValidateRequest(t, "/foo/bar", "GET", nil)
|
fakeHandler.ValidateRequest(t, "/foo/bar", "GET", nil)
|
||||||
|
|
|
@ -17,12 +17,10 @@ limitations under the License.
|
||||||
package cloudcfg
|
package cloudcfg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"gopkg.in/v1/yaml"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var storageToType = map[string]reflect.Type{
|
var storageToType = map[string]reflect.Type{
|
||||||
|
@ -41,9 +39,9 @@ func ToWireFormat(data []byte, storage string) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
obj := reflect.New(prototypeType).Interface()
|
obj := reflect.New(prototypeType).Interface()
|
||||||
err := yaml.Unmarshal(data, obj)
|
err := api.DecodeInto(data, obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return json.Marshal(obj)
|
return api.Encode(obj)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
package cloudcfg
|
package cloudcfg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
@ -32,7 +31,7 @@ func TestParseBadStorage(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func DoParseTest(t *testing.T, storage string, obj interface{}) {
|
func DoParseTest(t *testing.T, storage string, obj interface{}) {
|
||||||
json_data, _ := json.Marshal(obj)
|
json_data, _ := api.Encode(obj)
|
||||||
yaml_data, _ := yaml.Marshal(obj)
|
yaml_data, _ := yaml.Marshal(obj)
|
||||||
t.Logf("Intermediate yaml:\n%v\n", string(yaml_data))
|
t.Logf("Intermediate yaml:\n%v\n", string(yaml_data))
|
||||||
|
|
||||||
|
|
|
@ -31,23 +31,23 @@ import (
|
||||||
// ResourcePrinter is an interface that knows how to print API resources
|
// ResourcePrinter is an interface that knows how to print API resources
|
||||||
type ResourcePrinter interface {
|
type ResourcePrinter interface {
|
||||||
// Print receives an arbitrary JSON body, formats it and prints it to a writer
|
// Print receives an arbitrary JSON body, formats it and prints it to a writer
|
||||||
Print(string, io.Writer) error
|
Print([]byte, io.Writer) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identity printer simply copies the body out to the output stream
|
// Identity printer simply copies the body out to the output stream
|
||||||
type IdentityPrinter struct{}
|
type IdentityPrinter struct{}
|
||||||
|
|
||||||
func (i *IdentityPrinter) Print(data string, w io.Writer) error {
|
func (i *IdentityPrinter) Print(data []byte, w io.Writer) error {
|
||||||
_, err := fmt.Fprint(w, data)
|
_, err := w.Write(data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// YAMLPrinter parses JSON, and re-formats as YAML
|
// YAMLPrinter parses JSON, and re-formats as YAML
|
||||||
type YAMLPrinter struct{}
|
type YAMLPrinter struct{}
|
||||||
|
|
||||||
func (y *YAMLPrinter) Print(data string, w io.Writer) error {
|
func (y *YAMLPrinter) Print(data []byte, w io.Writer) error {
|
||||||
var obj interface{}
|
var obj interface{}
|
||||||
if err := json.Unmarshal([]byte(data), &obj); err != nil {
|
if err := json.Unmarshal(data, &obj); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
output, err := yaml.Marshal(obj)
|
output, err := yaml.Marshal(obj)
|
||||||
|
@ -64,9 +64,10 @@ type HumanReadablePrinter struct{}
|
||||||
var podColumns = []string{"Name", "Image(s)", "Host", "Labels"}
|
var podColumns = []string{"Name", "Image(s)", "Host", "Labels"}
|
||||||
var replicationControllerColumns = []string{"Name", "Image(s)", "Selector", "Replicas"}
|
var replicationControllerColumns = []string{"Name", "Image(s)", "Selector", "Replicas"}
|
||||||
var serviceColumns = []string{"Name", "Labels", "Selector", "Port"}
|
var serviceColumns = []string{"Name", "Labels", "Selector", "Port"}
|
||||||
|
var statusColumns = []string{"Status"}
|
||||||
|
|
||||||
func (h *HumanReadablePrinter) unknown(data string, w io.Writer) error {
|
func (h *HumanReadablePrinter) unknown(data []byte, w io.Writer) error {
|
||||||
_, err := fmt.Fprintf(w, "Unknown object: %s", data)
|
_, err := fmt.Fprintf(w, "Unknown object: %s", string(data))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,97 +91,62 @@ func (h *HumanReadablePrinter) makeImageList(manifest api.ContainerManifest) str
|
||||||
return strings.Join(images, ",")
|
return strings.Join(images, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HumanReadablePrinter) printPod(pod api.Pod, w io.Writer) error {
|
func (h *HumanReadablePrinter) printPod(pod *api.Pod, w io.Writer) error {
|
||||||
_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\n",
|
_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\n",
|
||||||
pod.ID, h.makeImageList(pod.DesiredState.Manifest), pod.CurrentState.Host+"/"+pod.CurrentState.HostIP, labels.Set(pod.Labels))
|
pod.ID, h.makeImageList(pod.DesiredState.Manifest), pod.CurrentState.Host+"/"+pod.CurrentState.HostIP, labels.Set(pod.Labels))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HumanReadablePrinter) printPodList(podList api.PodList, w io.Writer) error {
|
func (h *HumanReadablePrinter) printPodList(podList *api.PodList, w io.Writer) error {
|
||||||
for _, pod := range podList.Items {
|
for _, pod := range podList.Items {
|
||||||
if err := h.printPod(pod, w); err != nil {
|
if err := h.printPod(&pod, w); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HumanReadablePrinter) printReplicationController(ctrl api.ReplicationController, w io.Writer) error {
|
func (h *HumanReadablePrinter) printReplicationController(ctrl *api.ReplicationController, w io.Writer) error {
|
||||||
_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%d\n",
|
_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%d\n",
|
||||||
ctrl.ID, h.makeImageList(ctrl.DesiredState.PodTemplate.DesiredState.Manifest), labels.Set(ctrl.DesiredState.ReplicaSelector), ctrl.DesiredState.Replicas)
|
ctrl.ID, h.makeImageList(ctrl.DesiredState.PodTemplate.DesiredState.Manifest), labels.Set(ctrl.DesiredState.ReplicaSelector), ctrl.DesiredState.Replicas)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HumanReadablePrinter) printReplicationControllerList(list api.ReplicationControllerList, w io.Writer) error {
|
func (h *HumanReadablePrinter) printReplicationControllerList(list *api.ReplicationControllerList, w io.Writer) error {
|
||||||
for _, ctrl := range list.Items {
|
for _, ctrl := range list.Items {
|
||||||
if err := h.printReplicationController(ctrl, w); err != nil {
|
if err := h.printReplicationController(&ctrl, w); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HumanReadablePrinter) printService(svc api.Service, w io.Writer) error {
|
func (h *HumanReadablePrinter) printService(svc *api.Service, w io.Writer) error {
|
||||||
_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%d\n", svc.ID, labels.Set(svc.Labels), labels.Set(svc.Selector), svc.Port)
|
_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%d\n", svc.ID, labels.Set(svc.Labels), labels.Set(svc.Selector), svc.Port)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HumanReadablePrinter) printServiceList(list api.ServiceList, w io.Writer) error {
|
func (h *HumanReadablePrinter) printServiceList(list *api.ServiceList, w io.Writer) error {
|
||||||
for _, svc := range list.Items {
|
for _, svc := range list.Items {
|
||||||
if err := h.printService(svc, w); err != nil {
|
if err := h.printService(&svc, w); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO replace this with something that returns a concrete printer object, rather than
|
func (h *HumanReadablePrinter) printStatus(status *api.Status, w io.Writer) error {
|
||||||
// having the secondary switch below.
|
err := h.printHeader(statusColumns, w)
|
||||||
func (h *HumanReadablePrinter) extractObject(data, kind string) (interface{}, error) {
|
if err != nil {
|
||||||
// TODO: I think this can be replaced with some reflection and a map[string]type
|
return err
|
||||||
switch kind {
|
|
||||||
case "cluster#pod":
|
|
||||||
var obj api.Pod
|
|
||||||
if err := json.Unmarshal([]byte(data), &obj); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return obj, nil
|
|
||||||
case "cluster#podList":
|
|
||||||
var list api.PodList
|
|
||||||
if err := json.Unmarshal([]byte(data), &list); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return list, nil
|
|
||||||
case "cluster#replicationController":
|
|
||||||
var ctrl api.ReplicationController
|
|
||||||
if err := json.Unmarshal([]byte(data), &ctrl); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ctrl, nil
|
|
||||||
case "cluster#replicationControllerList":
|
|
||||||
var list api.ReplicationControllerList
|
|
||||||
if err := json.Unmarshal([]byte(data), &list); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return list, nil
|
|
||||||
case "cluster#service":
|
|
||||||
var ctrl api.Service
|
|
||||||
if err := json.Unmarshal([]byte(data), &ctrl); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ctrl, nil
|
|
||||||
case "cluster#serviceList":
|
|
||||||
var list api.ServiceList
|
|
||||||
if err := json.Unmarshal([]byte(data), &list); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return list, nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unknown kind: %s", kind)
|
|
||||||
}
|
}
|
||||||
|
_, err = fmt.Fprintf(w, "%v\n", status.Status)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HumanReadablePrinter) Print(data string, output io.Writer) error {
|
// TODO replace this with something that returns a concrete printer object, rather than
|
||||||
|
// having the secondary switch below.
|
||||||
|
func (h *HumanReadablePrinter) Print(data []byte, output io.Writer) error {
|
||||||
w := tabwriter.NewWriter(output, 20, 5, 3, ' ', 0)
|
w := tabwriter.NewWriter(output, 20, 5, 3, ' ', 0)
|
||||||
defer w.Flush()
|
defer w.Flush()
|
||||||
var mapObj map[string]interface{}
|
var mapObj map[string]interface{}
|
||||||
|
@ -198,30 +164,31 @@ func (h *HumanReadablePrinter) Print(data string, output io.Writer) error {
|
||||||
return fmt.Errorf("unexpected object with no 'kind' field: %s", data)
|
return fmt.Errorf("unexpected object with no 'kind' field: %s", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
kind := (mapObj["kind"]).(string)
|
obj, err := api.Decode(data)
|
||||||
obj, err := h.extractObject(data, kind)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
switch obj.(type) {
|
switch o := obj.(type) {
|
||||||
case api.Pod:
|
case *api.Pod:
|
||||||
h.printHeader(podColumns, w)
|
h.printHeader(podColumns, w)
|
||||||
return h.printPod(obj.(api.Pod), w)
|
return h.printPod(o, w)
|
||||||
case api.PodList:
|
case *api.PodList:
|
||||||
h.printHeader(podColumns, w)
|
h.printHeader(podColumns, w)
|
||||||
return h.printPodList(obj.(api.PodList), w)
|
return h.printPodList(o, w)
|
||||||
case api.ReplicationController:
|
case *api.ReplicationController:
|
||||||
h.printHeader(replicationControllerColumns, w)
|
h.printHeader(replicationControllerColumns, w)
|
||||||
return h.printReplicationController(obj.(api.ReplicationController), w)
|
return h.printReplicationController(o, w)
|
||||||
case api.ReplicationControllerList:
|
case *api.ReplicationControllerList:
|
||||||
h.printHeader(replicationControllerColumns, w)
|
h.printHeader(replicationControllerColumns, w)
|
||||||
return h.printReplicationControllerList(obj.(api.ReplicationControllerList), w)
|
return h.printReplicationControllerList(o, w)
|
||||||
case api.Service:
|
case *api.Service:
|
||||||
h.printHeader(serviceColumns, w)
|
h.printHeader(serviceColumns, w)
|
||||||
return h.printService(obj.(api.Service), w)
|
return h.printService(o, w)
|
||||||
case api.ServiceList:
|
case *api.ServiceList:
|
||||||
h.printHeader(serviceColumns, w)
|
h.printHeader(serviceColumns, w)
|
||||||
return h.printServiceList(obj.(api.ServiceList), w)
|
return h.printServiceList(o, w)
|
||||||
|
case *api.Status:
|
||||||
|
return h.printStatus(o, w)
|
||||||
default:
|
default:
|
||||||
return h.unknown(data, w)
|
return h.unknown(data, w)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@ limitations under the License.
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||||
|
@ -36,7 +34,7 @@ func MakeControllerRegistryStorage(registry ControllerRegistry) apiserver.RESTSt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *ControllerRegistryStorage) List(selector labels.Selector) (interface{}, error) {
|
func (storage *ControllerRegistryStorage) List(selector labels.Selector) (interface{}, error) {
|
||||||
result := api.ReplicationControllerList{JSONBase: api.JSONBase{Kind: "cluster#replicationControllerList"}}
|
result := api.ReplicationControllerList{}
|
||||||
controllers, err := storage.registry.ListControllers()
|
controllers, err := storage.registry.ListControllers()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, controller := range controllers {
|
for _, controller := range controllers {
|
||||||
|
@ -53,18 +51,16 @@ func (storage *ControllerRegistryStorage) Get(id string) (interface{}, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
controller.Kind = "cluster#replicationController"
|
|
||||||
return controller, err
|
return controller, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *ControllerRegistryStorage) Delete(id string) (<-chan interface{}, error) {
|
func (storage *ControllerRegistryStorage) Delete(id string) (<-chan interface{}, error) {
|
||||||
return apiserver.MakeAsync(func() interface{} { return apiserver.Status{Success: true} }), storage.registry.DeleteController(id)
|
return apiserver.MakeAsync(func() interface{} { return api.Status{Status: api.StatusSuccess} }), storage.registry.DeleteController(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *ControllerRegistryStorage) Extract(body string) (interface{}, error) {
|
func (storage *ControllerRegistryStorage) Extract(body []byte) (interface{}, error) {
|
||||||
result := api.ReplicationController{}
|
result := api.ReplicationController{}
|
||||||
err := json.Unmarshal([]byte(body), &result)
|
err := api.DecodeInto(body, &result)
|
||||||
result.Kind = "cluster#replicationController"
|
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,12 +122,10 @@ func TestExtractControllerJson(t *testing.T) {
|
||||||
ID: "foo",
|
ID: "foo",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
body, err := json.Marshal(controller)
|
body, err := api.Encode(&controller)
|
||||||
expectNoError(t, err)
|
expectNoError(t, err)
|
||||||
controllerOut, err := storage.Extract(string(body))
|
controllerOut, err := storage.Extract(body)
|
||||||
expectNoError(t, err)
|
expectNoError(t, err)
|
||||||
// Extract adds a Kind
|
|
||||||
controller.Kind = "cluster#replicationController"
|
|
||||||
if !reflect.DeepEqual(controller, controllerOut) {
|
if !reflect.DeepEqual(controller, controllerOut) {
|
||||||
t.Errorf("Expected %#v, found %#v", controller, controllerOut)
|
t.Errorf("Expected %#v, found %#v", controller, controllerOut)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -74,7 +73,6 @@ func (storage *PodRegistryStorage) List(selector labels.Selector) (interface{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Kind = "cluster#podList"
|
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,18 +127,16 @@ func (storage *PodRegistryStorage) Get(id string) (interface{}, error) {
|
||||||
}
|
}
|
||||||
pod.CurrentState.HostIP = getInstanceIP(storage.cloud, pod.CurrentState.Host)
|
pod.CurrentState.HostIP = getInstanceIP(storage.cloud, pod.CurrentState.Host)
|
||||||
|
|
||||||
pod.Kind = "cluster#pod"
|
|
||||||
return pod, err
|
return pod, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *PodRegistryStorage) Delete(id string) (<-chan interface{}, error) {
|
func (storage *PodRegistryStorage) Delete(id string) (<-chan interface{}, error) {
|
||||||
return apiserver.MakeAsync(func() interface{} { return apiserver.Status{Success: true} }), storage.registry.DeletePod(id)
|
return apiserver.MakeAsync(func() interface{} { return api.Status{Status: api.StatusSuccess} }), storage.registry.DeletePod(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storage *PodRegistryStorage) Extract(body string) (interface{}, error) {
|
func (storage *PodRegistryStorage) Extract(body []byte) (interface{}, error) {
|
||||||
pod := api.Pod{}
|
pod := api.Pod{}
|
||||||
err := json.Unmarshal([]byte(body), &pod)
|
err := api.DecodeInto(body, &pod)
|
||||||
pod.Kind = "cluster#pod"
|
|
||||||
return pod, err
|
return pod, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -103,12 +102,10 @@ func TestExtractJson(t *testing.T) {
|
||||||
ID: "foo",
|
ID: "foo",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
body, err := json.Marshal(pod)
|
body, err := api.Encode(&pod)
|
||||||
expectNoError(t, err)
|
expectNoError(t, err)
|
||||||
podOut, err := storage.Extract(string(body))
|
podOut, err := storage.Extract(body)
|
||||||
expectNoError(t, err)
|
expectNoError(t, err)
|
||||||
// Extract adds in a kind
|
|
||||||
pod.Kind = "cluster#pod"
|
|
||||||
if !reflect.DeepEqual(pod, podOut) {
|
if !reflect.DeepEqual(pod, podOut) {
|
||||||
t.Errorf("Expected %#v, found %#v", pod, podOut)
|
t.Errorf("Expected %#v, found %#v", pod, podOut)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -64,7 +63,6 @@ func (sr *ServiceRegistryStorage) List(selector labels.Selector) (interface{}, e
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
list.Kind = "cluster#serviceList"
|
|
||||||
var filtered []api.Service
|
var filtered []api.Service
|
||||||
for _, service := range list.Items {
|
for _, service := range list.Items {
|
||||||
if selector.Matches(labels.Set(service.Labels)) {
|
if selector.Matches(labels.Set(service.Labels)) {
|
||||||
|
@ -80,7 +78,6 @@ func (sr *ServiceRegistryStorage) Get(id string) (interface{}, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
service.Kind = "cluster#service"
|
|
||||||
return service, err
|
return service, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,13 +99,12 @@ func (sr *ServiceRegistryStorage) Delete(id string) (<-chan interface{}, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return apiserver.MakeAsync(func() interface{} { return apiserver.Status{Success: true} }), sr.registry.DeleteService(id)
|
return apiserver.MakeAsync(func() interface{} { return api.Status{Status: api.StatusSuccess} }), sr.registry.DeleteService(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sr *ServiceRegistryStorage) Extract(body string) (interface{}, error) {
|
func (sr *ServiceRegistryStorage) Extract(body []byte) (interface{}, error) {
|
||||||
var svc api.Service
|
var svc api.Service
|
||||||
err := json.Unmarshal([]byte(body), &svc)
|
err := api.DecodeInto(body, &svc)
|
||||||
svc.Kind = "cluster#service"
|
|
||||||
return svc, err
|
return svc, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue