Skip to content

Commit

Permalink
Merge pull request kubernetes#888 from csrwng/pluggable_type_parsing
Browse files Browse the repository at this point in the history
Allow kubecfg to parse other types via register function
  • Loading branch information
smarterclayton committed Aug 14, 2014
2 parents 8daf8c7 + 5538bfc commit fadf1b8
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 18 deletions.
14 changes: 11 additions & 3 deletions cmd/kubecfg/kubecfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 :,..., :] <method>
Expand All @@ -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, "|")
}
Expand All @@ -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)
}
Expand Down Expand Up @@ -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
}
Expand Down
23 changes: 14 additions & 9 deletions pkg/kubecfg/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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
Expand Down
36 changes: 30 additions & 6 deletions pkg/kubecfg/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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"},
Expand All @@ -68,7 +75,7 @@ func TestParsePod(t *testing.T) {
},
},
},
})
}, testParser)
}

func TestParseService(t *testing.T) {
Expand All @@ -81,7 +88,7 @@ func TestParseService(t *testing.T) {
Selector: map[string]string{
"area": "staging",
},
})
}, testParser)
}

func TestParseController(t *testing.T) {
Expand All @@ -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)
}

0 comments on commit fadf1b8

Please sign in to comment.