diff --git a/fn.go b/fn.go index d03eccc..62978b2 100644 --- a/fn.go +++ b/fn.go @@ -18,17 +18,15 @@ import ( "k8s.io/apimachinery/pkg/util/json" "k8s.io/apimachinery/pkg/util/yaml" + "github.com/crossplane-contrib/function-go-templating/input/v1beta1" "github.com/crossplane/crossplane-runtime/pkg/fieldpath" "github.com/crossplane/crossplane-runtime/pkg/meta" - "github.com/crossplane/function-sdk-go/errors" "github.com/crossplane/function-sdk-go/logging" fnv1 "github.com/crossplane/function-sdk-go/proto/v1" "github.com/crossplane/function-sdk-go/request" "github.com/crossplane/function-sdk-go/resource" "github.com/crossplane/function-sdk-go/response" - - "github.com/crossplane-contrib/function-go-templating/input/v1beta1" ) // osFS is a dead-simple implementation of [io/fs.FS] that just wraps around @@ -43,8 +41,9 @@ func (*osFS) Open(name string) (fs.File, error) { type Function struct { fnv1.UnimplementedFunctionRunnerServiceServer - log logging.Logger - fsys fs.FS + log logging.Logger + fsys fs.FS + defaultSource string } type YamlErrorContext struct { @@ -72,6 +71,12 @@ func (f *Function) RunFunction(_ context.Context, req *fnv1.RunFunctionRequest) response.Fatal(rsp, errors.Wrapf(err, "cannot get Function input from %T", req)) return rsp, nil } + if in.Source == "" && f.defaultSource != "" { + in.Source = v1beta1.FileSystemSource + in.FileSystem = &v1beta1.TemplateSourceFileSystem{ + DirPath: f.defaultSource, + } + } tg, err := NewTemplateSourceGetter(f.fsys, req.GetContext(), in) if err != nil { diff --git a/fn_test.go b/fn_test.go index 008ebb3..8a653c2 100644 --- a/fn_test.go +++ b/fn_test.go @@ -12,13 +12,11 @@ import ( "google.golang.org/protobuf/types/known/durationpb" "k8s.io/utils/ptr" + "github.com/crossplane-contrib/function-go-templating/input/v1beta1" "github.com/crossplane/crossplane-runtime/pkg/logging" - fnv1 "github.com/crossplane/function-sdk-go/proto/v1" "github.com/crossplane/function-sdk-go/resource" "github.com/crossplane/function-sdk-go/response" - - "github.com/crossplane-contrib/function-go-templating/input/v1beta1" ) var ( @@ -71,8 +69,9 @@ metadata: func TestRunFunction(t *testing.T) { type args struct { - ctx context.Context - req *fnv1.RunFunctionRequest + ctx context.Context + req *fnv1.RunFunctionRequest + defaultSource string } type want struct { rsp *fnv1.RunFunctionResponse @@ -192,6 +191,28 @@ func TestRunFunction(t *testing.T) { }, }, }, + "DefaultSourceDoesNotExist": { + // We can't easily inject a filesystem with valid input into the + // test, so just make sure the default source is used and assume it + // would work properly if it pointed to something valid. + reason: "The default source should be used if specified when the input is empty", + args: args{ + req: &fnv1.RunFunctionRequest{}, + defaultSource: "does/not/exist", + }, + want: want{ + rsp: &fnv1.RunFunctionResponse{ + Meta: &fnv1.ResponseMeta{Ttl: durationpb.New(response.DefaultTTL)}, + Results: []*fnv1.Result{ + { + Severity: fnv1.Severity_SEVERITY_FATAL, + Message: "invalid function input: cannot read tmpl from the folder {does/not/exist}: open does/not/exist: file does not exist", + Target: fnv1.Target_TARGET_COMPOSITE.Enum(), + }, + }, + }, + }, + }, "NoResourceNameAnnotation": { reason: "The Function should return a fatal result if the cd does not have a composition-resource-name annotation", args: args{ @@ -1403,8 +1424,9 @@ func TestRunFunction(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { f := &Function{ - log: logging.NewNopLogger(), - fsys: testdataFS, + log: logging.NewNopLogger(), + fsys: testdataFS, + defaultSource: tc.args.defaultSource, } rsp, err := f.RunFunction(tc.args.ctx, tc.args.req) diff --git a/main.go b/main.go index 0329300..24a89df 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,6 @@ package main import ( "github.com/alecthomas/kong" - "github.com/crossplane/function-sdk-go" ) @@ -16,6 +15,8 @@ type CLI struct { TLSCertsDir string `help:"Directory containing server certs (tls.key, tls.crt) and the CA used to verify client certificates (ca.crt)" env:"TLS_SERVER_CERTS_DIR"` Insecure bool `help:"Run without mTLS credentials. If you supply this flag --tls-server-certs-dir will be ignored."` MaxRecvMessageSize int `help:"Maximum size of received messages in MB." default:"4"` + + DefaultSource string `help:"Default template source to use when input is not provided to the function." default:"" env:"FUNCTION_GO_TEMPLATING_DEFAULT_SOURCE"` } // Run this Function. @@ -27,8 +28,9 @@ func (c *CLI) Run() error { return function.Serve( &Function{ - log: log, - fsys: &osFS{}, + log: log, + fsys: &osFS{}, + defaultSource: c.DefaultSource, }, function.Listen(c.Network, c.Address), function.MTLSCertificates(c.TLSCertsDir),