diff --git a/cmd/kubecfg/kubecfg.go b/cmd/kubecfg/kubecfg.go index c99006af06..4ba51cd186 100644 --- a/cmd/kubecfg/kubecfg.go +++ b/cmd/kubecfg/kubecfg.go @@ -57,6 +57,13 @@ var ( templateStr = flag.String("template", "", "If present, parse this string as a golang template and use it for output printing") ) +var parser = kubecfg.NewParser(map[string]interface{}{ + "pods": api.Pod{}, + "services": api.Service{}, + "replicationControllers": api.ReplicationController{}, + "minions": api.Minion{}, +}) + func usage() { fmt.Fprintf(os.Stderr, `usage: kubecfg -h [-c config/file.json] [-p :,..., :] @@ -71,10 +78,11 @@ func usage() { Options: `, prettyWireStorage()) flag.PrintDefaults() + } func prettyWireStorage() string { - types := kubecfg.SupportedWireStorage() + types := parser.SupportedWireStorage() sort.Strings(types) return strings.Join(types, "|") } @@ -89,7 +97,7 @@ func readConfig(storage string) []byte { if err != nil { glog.Fatalf("Unable to read %v: %v\n", *config, err) } - data, err = kubecfg.ToWireFormat(data, storage) + data, err = parser.ToWireFormat(data, storage) if err != nil { glog.Fatalf("Error parsing %v as an object for %v: %v\n", *config, storage, err) } @@ -190,7 +198,7 @@ func storagePathFromArg(arg string) (storage, path string, hasSuffix bool) { //checkStorage returns true if the provided storage is valid func checkStorage(storage string) bool { - for _, allowed := range kubecfg.SupportedWireStorage() { + for _, allowed := range parser.SupportedWireStorage() { if allowed == storage { return true } diff --git a/pkg/kubecfg/parse.go b/pkg/kubecfg/parse.go index a09328db94..984747c47e 100644 --- a/pkg/kubecfg/parse.go +++ b/pkg/kubecfg/parse.go @@ -23,17 +23,22 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" ) -var storageToType = map[string]reflect.Type{ - "pods": reflect.TypeOf(api.Pod{}), - "services": reflect.TypeOf(api.Service{}), - "replicationControllers": reflect.TypeOf(api.ReplicationController{}), - "minions": reflect.TypeOf(api.Minion{}), +type Parser struct { + storageToType map[string]reflect.Type +} + +func NewParser(objectMap map[string]interface{}) *Parser { + typeMap := make(map[string]reflect.Type) + for name, obj := range objectMap { + typeMap[name] = reflect.TypeOf(obj) + } + return &Parser{typeMap} } // ToWireFormat takes input 'data' as either json or yaml, checks that it parses as the // appropriate object type, and returns json for sending to the API or an error. -func ToWireFormat(data []byte, storage string) ([]byte, error) { - prototypeType, found := storageToType[storage] +func (p *Parser) ToWireFormat(data []byte, storage string) ([]byte, error) { + prototypeType, found := p.storageToType[storage] if !found { return nil, fmt.Errorf("unknown storage type: %v", storage) } @@ -46,9 +51,9 @@ func ToWireFormat(data []byte, storage string) ([]byte, error) { return api.Encode(obj) } -func SupportedWireStorage() []string { +func (p *Parser) SupportedWireStorage() []string { types := []string{} - for k := range storageToType { + for k := range p.storageToType { types = append(types, k) } return types diff --git a/pkg/kubecfg/parse_test.go b/pkg/kubecfg/parse_test.go index 1fd36ad9e1..baada2514e 100644 --- a/pkg/kubecfg/parse_test.go +++ b/pkg/kubecfg/parse_test.go @@ -24,19 +24,20 @@ import ( ) func TestParseBadStorage(t *testing.T) { - _, err := ToWireFormat([]byte("{}"), "badstorage") + p := NewParser(map[string]interface{}{}) + _, err := p.ToWireFormat([]byte("{}"), "badstorage") if err == nil { t.Errorf("Expected error, received none") } } -func DoParseTest(t *testing.T, storage string, obj interface{}) { +func DoParseTest(t *testing.T, storage string, obj interface{}, p *Parser) { jsonData, _ := api.Encode(obj) yamlData, _ := yaml.Marshal(obj) t.Logf("Intermediate yaml:\n%v\n", string(yamlData)) t.Logf("Intermediate json:\n%v\n", string(jsonData)) - jsonGot, jsonErr := ToWireFormat(jsonData, storage) - yamlGot, yamlErr := ToWireFormat(yamlData, storage) + jsonGot, jsonErr := p.ToWireFormat(jsonData, storage) + yamlGot, yamlErr := p.ToWireFormat(yamlData, storage) if jsonErr != nil { t.Errorf("json err: %#v", jsonErr) @@ -54,6 +55,12 @@ func DoParseTest(t *testing.T, storage string, obj interface{}) { } } +var testParser = NewParser(map[string]interface{}{ + "pods": api.Pod{}, + "services": api.Service{}, + "replicationControllers": api.ReplicationController{}, +}) + func TestParsePod(t *testing.T) { DoParseTest(t, "pods", api.Pod{ JSONBase: api.JSONBase{APIVersion: "v1beta1", ID: "test pod", Kind: "Pod"}, @@ -68,7 +75,7 @@ func TestParsePod(t *testing.T) { }, }, }, - }) + }, testParser) } func TestParseService(t *testing.T) { @@ -81,7 +88,7 @@ func TestParseService(t *testing.T) { Selector: map[string]string{ "area": "staging", }, - }) + }, testParser) } func TestParseController(t *testing.T) { @@ -103,5 +110,22 @@ func TestParseController(t *testing.T) { }, }, }, - }) + }, testParser) +} + +type TestParseType struct { + api.JSONBase `json:",inline" yaml:",inline"` + Data string `json:"data" yaml:"data"` +} + +func TestParseCustomType(t *testing.T) { + api.AddKnownTypes("", TestParseType{}) + api.AddKnownTypes("v1beta1", TestParseType{}) + parser := NewParser(map[string]interface{}{ + "custom": TestParseType{}, + }) + DoParseTest(t, "custom", TestParseType{ + JSONBase: api.JSONBase{APIVersion: "", ID: "my custom object", Kind: "TestParseType"}, + Data: "test data", + }, parser) }