pkg/types: add IgnoreUnknown arg and logic
authorStefan Junker <mail@stefanjunker.de>
Thu, 17 Mar 2016 13:08:29 +0000 (14:08 +0100)
committerStefan Junker <mail@stefanjunker.de>
Mon, 21 Mar 2016 19:36:05 +0000 (20:36 +0100)
This commit adds a struct type CommonArgs that is to be embedded in
every plugin's argument struct. It contains a field named
"IgnoreUnknown" which will be parsed as a boolean and can be provided to
ignore unknown arguments passed to the plugin.

pkg/types/args.go
plugins/ipam/host-local/config.go

index 3c0fd88..c4e3c55 100644 (file)
@@ -21,6 +21,39 @@ import (
        "strings"
 )
 
+// UnmarshallableBool typedef for builtin bool
+// because builtin type's methods can't be declared
+type UnmarshallableBool bool
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+// Returns boolean true if the string is "1" or "[Tt]rue"
+// Returns boolean false if the string is "0" or "[Ff]alse"
+func (b *UnmarshallableBool) UnmarshalText(data []byte) error {
+       s := strings.ToLower(string(data))
+       switch s {
+       case "1", "true":
+               *b = true
+       case "0", "false":
+               *b = false
+       default:
+               return fmt.Errorf("Boolean unmarshal error: invalid input %s", s)
+       }
+       return nil
+}
+
+// CommonArgs contains the IgnoreUnknown argument
+// and must be embedded by all Arg structs
+type CommonArgs struct {
+       IgnoreUnknown UnmarshallableBool `json:"ignoreunknown,omitempty"`
+}
+
+// getKeyField is a helper function to receive Values
+// Values that represent a pointer to a struct
+func getKeyField(keyString string, v reflect.Value) reflect.Value {
+       return v.Elem().FieldByName(keyString)
+}
+
+// LoadArgs parses args from a string in the form "K=V;K2=V2;..."
 func LoadArgs(args string, container interface{}) error {
        if args == "" {
                return nil
@@ -29,6 +62,7 @@ func LoadArgs(args string, container interface{}) error {
        containerValue := reflect.ValueOf(container)
 
        pairs := strings.Split(args, ";")
+       unknownArgs := []string{}
        for _, pair := range pairs {
                kv := strings.Split(pair, "=")
                if len(kv) != 2 {
@@ -36,15 +70,22 @@ func LoadArgs(args string, container interface{}) error {
                }
                keyString := kv[0]
                valueString := kv[1]
-               keyField := containerValue.Elem().FieldByName(keyString)
+               keyField := GetKeyField(keyString, containerValue)
                if !keyField.IsValid() {
-                       return fmt.Errorf("ARGS: invalid key %q", keyString)
+                       unknownArgs = append(unknownArgs, pair)
+                       continue
                }
+
                u := keyField.Addr().Interface().(encoding.TextUnmarshaler)
                err := u.UnmarshalText([]byte(valueString))
                if err != nil {
                        return fmt.Errorf("ARGS: error parsing value of pair %q: %v)", pair, err)
                }
        }
+
+       isIgnoreUnknown := GetKeyField("IgnoreUnknown", containerValue).Bool()
+       if len(unknownArgs) > 0 && !isIgnoreUnknown {
+               return fmt.Errorf("ARGS: unknown args %q", unknownArgs)
+       }
        return nil
 }
index c33c33c..08ca07e 100644 (file)
@@ -35,6 +35,7 @@ type IPAMConfig struct {
 }
 
 type IPAMArgs struct {
+       types.CommonArgs
        IP net.IP `json:"ip,omitempty"`
 }