diff --git a/go/fn/examples/data/runner-configmap-general.yaml b/go/fn/examples/data/runner-configmap-general.yaml new file mode 100644 index 000000000..349e3d9db --- /dev/null +++ b/go/fn/examples/data/runner-configmap-general.yaml @@ -0,0 +1,15 @@ +apiVersion: config.kubernetes.io/v1 +kind: ResourceList +items: + - apiVersion: v1 + kind: Service + metadata: + name: example +functionConfig: + apiVersion: v1 + kind: ConfigMap + metadata: + name: runner-fn-config + data: + project-id: kpt-dev + managed-by: kpt diff --git a/go/fn/examples/data/runner-configmap.yaml b/go/fn/examples/data/runner-configmap.yaml new file mode 100644 index 000000000..6c5f604bb --- /dev/null +++ b/go/fn/examples/data/runner-configmap.yaml @@ -0,0 +1,15 @@ +apiVersion: config.kubernetes.io/v1 +kind: ResourceList +items: + - apiVersion: v1 + kind: Service + metadata: + name: example +functionConfig: + apiVersion: v1 + kind: ConfigMap + metadata: + name: customConfig + data: + owner: kpt + org: google diff --git a/go/fn/examples/data/setlabels-resourcelist.yaml b/go/fn/examples/data/runner-customFnConfig.yaml similarity index 71% rename from go/fn/examples/data/setlabels-resourcelist.yaml rename to go/fn/examples/data/runner-customFnConfig.yaml index 62570781f..62eaf76b4 100644 --- a/go/fn/examples/data/setlabels-resourcelist.yaml +++ b/go/fn/examples/data/runner-customFnConfig.yaml @@ -7,6 +7,8 @@ items: name: example functionConfig: apiVersion: fn.kpt.dev/v1alpha1 - kind: SetLabels + kind: CustomFnConfig metadata: - name: setlabel-fn-config + name: runner-fn-config + owner: kpt + org: google diff --git a/go/fn/examples/example_asmain_runner_test.go b/go/fn/examples/example_asmain_runner_test.go index 7350f98e4..c04e4c4b0 100644 --- a/go/fn/examples/example_asmain_runner_test.go +++ b/go/fn/examples/example_asmain_runner_test.go @@ -19,43 +19,108 @@ import ( "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" ) +var _ fn.Runner = &CustomFnConfig{} + +type CustomFnConfig struct { + Owner string + Org string +} + +// Run is the main function logic. +// `ctx` provides easy methods to add info, error or warning result to `ResourceList.Results`. +// `items` is parsed from the STDIN "ResourceList.Items". +// `functionConfig` is from the STDIN "ResourceList.FunctionConfig". The value is parsed from a `CustomFnConfig` type +// "owner" and "org" field. +func (r *CustomFnConfig) Run(ctx *fn.Context, functionConfig *fn.KubeObject, items fn.KubeObjects) { + for _, o := range items { + o.SetName(r.Owner) + o.SetNamespace(r.Org) + } + ctx.ResultInfo("updated namespace and name", nil) +} + +// This example uses a CustomFnConfig object, which implements `Runner.Run` methods. +func Example_asMainCustomFnConfig() { + file, _ := os.Open("./data/runner-customFnConfig.yaml") + defer file.Close() + os.Stdin = file + + if err := fn.AsMain(&CustomFnConfig{}); err != nil { + os.Exit(1) + } + // Output: + // apiVersion: config.kubernetes.io/v1 + // kind: ResourceList + // items: + // - apiVersion: v1 + // kind: Service + // metadata: + // name: kpt + // namespace: google + // functionConfig: + // apiVersion: fn.kpt.dev/v1alpha1 + // kind: CustomFnConfig + // metadata: + // name: runner-fn-config + // owner: kpt + // org: google + // results: + // - message: updated namespace and name + // severity: info +} + +func Example_asMainConfigMap() { + file, _ := os.Open("./data/runner-configmap.yaml") + defer file.Close() + os.Stdin = file + + if err := fn.AsMain(&CustomFnConfig{}); err != nil { + os.Exit(1) + } + // Output: + // apiVersion: config.kubernetes.io/v1 + // kind: ResourceList + // items: + // - apiVersion: v1 + // kind: Service + // metadata: + // name: kpt + // namespace: google + // functionConfig: + // apiVersion: v1 + // kind: ConfigMap + // metadata: + // name: customConfig + // data: + // owner: kpt + // org: google + // results: + // - message: updated namespace and name + // severity: info +} + var _ fn.Runner = &SetLabels{} type SetLabels struct { - Labels map[string]string `json:"labels,omitempty"` + Data map[string]string } // Run is the main function logic. // `ctx` provides easy methods to add info, error or warning result to `ResourceList.Results`. // `items` is parsed from the STDIN "ResourceList.Items". -// `functionConfig` is from the STDIN "ResourceList.FunctionConfig". The value has been assigned to the r.Labels -// the functionConfig is validated to have kind "SetLabels" and apiVersion "fn.kpt.dev/v1alpha1" -func (r *SetLabels) Run(ctx *fn.Context, functionConfig *fn.KubeObject, items []*fn.KubeObject) { +// `functionConfig` is from the STDIN "ResourceList.FunctionConfig". The value is parsed from a `ConfigMap` type +// "data" field. +func (r *SetLabels) Run(ctx *fn.Context, functionConfig *fn.KubeObject, items fn.KubeObjects) { for _, o := range items { - for k, newLabel := range r.Labels { - o.SetLabel(k, newLabel) + for k, v := range r.Data { + o.SetLabel(k, v) } } ctx.ResultInfo("updated labels", nil) } -// This example uses a SetLabels object, which implements `Runner.Run` methods. -// -// The input from ./data/setlabels-resourcelist.yaml: -// apiVersion: config.kubernetes.io/v1 -// kind: ResourceList -// items: -// - apiVersion: v1 -// kind: Service -// metadata: -// name: example -// functionConfig: -// apiVersion: fn.kpt.dev/v1alpha1 -// kind: SetLabels -// metadata: -// name: setlabel-fn-config -func Example_asMain() { - file, _ := os.Open("./data/setlabels-resourcelist.yaml") +func Example_asMain_configMapData() { + file, _ := os.Open("./data/runner-configmap-general.yaml") defer file.Close() os.Stdin = file @@ -70,11 +135,17 @@ func Example_asMain() { // kind: Service // metadata: // name: example + // labels: + // project-id: kpt-dev + // managed-by: kpt // functionConfig: - // apiVersion: fn.kpt.dev/v1alpha1 - // kind: SetLabels + // apiVersion: v1 + // kind: ConfigMap // metadata: - // name: setlabel-fn-config + // name: runner-fn-config + // data: + // project-id: kpt-dev + // managed-by: kpt // results: // - message: updated labels // severity: info diff --git a/go/fn/functionrunner.go b/go/fn/functionrunner.go index bd5d55777..e3ffa726c 100644 --- a/go/fn/functionrunner.go +++ b/go/fn/functionrunner.go @@ -15,5 +15,5 @@ package fn type Runner interface { - Run(context *Context, functionConfig *KubeObject, items []*KubeObject) + Run(context *Context, functionConfig *KubeObject, items KubeObjects) } diff --git a/go/fn/runnerProcessor.go b/go/fn/runnerProcessor.go index 14dc77b4f..889748d73 100644 --- a/go/fn/runnerProcessor.go +++ b/go/fn/runnerProcessor.go @@ -17,6 +17,7 @@ package fn import ( "fmt" "reflect" + "strings" ) type runnerProcessor struct { @@ -39,9 +40,19 @@ func (r *runnerProcessor) config(ctx *Context, o *KubeObject) { data := o.NestedStringMapOrDie("data") fnRunnerElem := reflect.ValueOf(r.fnRunner).Elem() for i := 0; i < fnRunnerElem.NumField(); i++ { - if fnRunnerElem.Field(i).Kind() == reflect.Map { - fnRunnerElem.Field(i).Set(reflect.ValueOf(data)) - break + switch fnRunnerElem.Field(i).Kind() { + case reflect.String: + for k, v := range data { + lowerKey := strings.ToLower(k) + if lowerKey == strings.ToLower(fnRunnerElem.Type().Field(i).Name) { + fnRunnerElem.Field(i).SetString(v) + break + } + } + case reflect.Map: + if "Data" == fnRunnerElem.Type().Field(i).Name { + fnRunnerElem.Field(i).Set(reflect.ValueOf(data)) + } } } case o.IsGVK("fn.kpt.dev", "v1alpha1", fnName):