From bf2c9d33cce8fe25bbb0a834909b84fcbe1e0ff6 Mon Sep 17 00:00:00 2001 From: Andrew Su Date: Wed, 4 May 2022 17:38:07 -0400 Subject: [PATCH] Update Java buildpack detect and build The detect now checks for func.yaml OR they explicitly defined an environment variable for the function name or package scan path Signed-off-by: Andrew Su --- buildpacks/java/buildpack.toml | 12 ++++ buildpacks/java/java/build.go | 15 +++-- buildpacks/java/java/detect.go | 65 +++++++++++---------- buildpacks/java/java/func_yaml_envs.go | 81 ++++++++++++++++++++++++++ buildpacks/java/java/function.go | 43 +++++++------- 5 files changed, 160 insertions(+), 56 deletions(-) create mode 100644 buildpacks/java/java/func_yaml_envs.go diff --git a/buildpacks/java/buildpack.toml b/buildpacks/java/buildpack.toml index 6fc343e7..1270f7f9 100644 --- a/buildpacks/java/buildpack.toml +++ b/buildpacks/java/buildpack.toml @@ -13,6 +13,18 @@ api = "0.6" include-files = ["README.md", "bin/build", "bin/detect", "bin/main", "buildpack.toml", "VERSION"] pre-package = "./build.sh" + [[metadata.configurations]] + build = true + default = "" + description = "The function to run" + name = "BP_FUNCTION" + + [[metadata.configurations]] + build = true + default = "functions" + description = "The packages to scan for functions, the default is 'functions'" + name = "BP_FUNCTION_PACKAGES" + [[metadata.dependencies]] id = "invoker" name = "Java Invoker" diff --git a/buildpacks/java/java/build.go b/buildpacks/java/java/build.go index a3fe5036..0197fd84 100644 --- a/buildpacks/java/java/build.go +++ b/buildpacks/java/java/build.go @@ -22,7 +22,7 @@ func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) { b.Logger.Title(context.Buildpack) result := libcnb.NewBuildResult() - _, err := libpak.NewConfigurationResolver(context.Buildpack, &b.Logger) + cr, err := libpak.NewConfigurationResolver(context.Buildpack, &b.Logger) if err != nil { return libcnb.BuildResult{}, fmt.Errorf("unable to create configuration resolver\n%w", err) } @@ -47,6 +47,11 @@ func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) { if !ok { return result, nil } + if e.Metadata["has_func_yaml"] == true { + envs := NewFuncYamlEnvs(context.Application.Path) + envs.Logger = b.Logger + result.Layers = append(result.Layers, envs) + } dep, err := dr.Resolve("invoker", "") if err != nil { @@ -71,10 +76,10 @@ func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) { result.BOM.Entries = append(result.BOM.Entries, be) } - f := NewFunction(e, context.Application.Path) - if err != nil { - return libcnb.BuildResult{}, fmt.Errorf("unable to create function\n%w", err) - } + funcDef, _ := cr.Resolve("BP_FUNCTION") + funcPackages, _ := cr.Resolve("BP_FUNCTION_PACKAGES") + + f := NewFunction(funcPackages, funcDef, context.Application.Path) f.Logger = b.Logger result.Layers = append(result.Layers, f) diff --git a/buildpacks/java/java/detect.go b/buildpacks/java/java/detect.go index 49e84576..ae477883 100644 --- a/buildpacks/java/java/detect.go +++ b/buildpacks/java/java/detect.go @@ -9,6 +9,7 @@ import ( "path/filepath" "github.com/buildpacks/libcnb" + "github.com/paketo-buildpacks/libpak" "github.com/paketo-buildpacks/libpak/bard" knfn "knative.dev/kn-plugin-func" ) @@ -17,22 +18,45 @@ type Detect struct { Logger bard.Logger } -func (d Detect) Detect(context libcnb.DetectContext) (libcnb.DetectResult, error) { - result := libcnb.DetectResult{} +func (d Detect) checkConfigs(cr libpak.ConfigurationResolver) bool { + if _, defined := cr.Resolve("BP_FUNCTION"); defined { + return true + } + + if _, defined := cr.Resolve("BP_FUNCTION_PACKAGES"); defined { + return true + } + + return false +} - configFile := filepath.Join(context.Application.Path, knfn.ConfigFile) +func (d Detect) checkFuncYaml(appPath string) bool { + configFile := filepath.Join(appPath, knfn.ConfigFile) _, err := os.Stat(configFile) if err != nil { - d.logf(fmt.Sprintf("unable to find file '%s'", configFile)) - return result, nil + d.Logger.Bodyf("unable to find file '%s'", configFile) + return false } - f, err := knfn.NewFunction(context.Application.Path) + return true +} + +func (d Detect) Detect(context libcnb.DetectContext) (libcnb.DetectResult, error) { + result := libcnb.DetectResult{} + + appPath := context.Application.Path + funcYamlPass := d.checkFuncYaml(appPath) + + cr, err := libpak.NewConfigurationResolver(context.Buildpack, &d.Logger) if err != nil { - return result, fmt.Errorf("parsing function config: %v", err) + return result, fmt.Errorf("unable to create configuration resolver: %v", err) } - envs := envsToMap(f.Envs) + configPass := d.checkConfigs(cr) + if err != nil { + d.Logger.Bodyf("unable to check buildpack configurations: %v", err) + return result, nil + } result.Plans = append(result.Plans, libcnb.BuildPlan{ Provides: []libcnb.BuildPlanProvide{ @@ -44,8 +68,8 @@ func (d Detect) Detect(context libcnb.DetectContext) (libcnb.DetectResult, error { Name: "java-function", Metadata: map[string]interface{}{ - "launch": true, - "envs": envs, + "launch": true, + "has_func_yaml": funcYamlPass, }, }, { @@ -60,25 +84,6 @@ func (d Detect) Detect(context libcnb.DetectContext) (libcnb.DetectResult, error }, }) - result.Pass = true + result.Pass = funcYamlPass || configPass return result, nil } - -func (d Detect) logf(format string, args ...interface{}) { - d.Logger.Infof(format, args...) -} - -func envsToMap(envs knfn.Envs) map[string]string { - result := map[string]string{} - - for _, e := range envs { - key := *e.Name - val := "" - if e.Value != nil { - val = *e.Value - } - result[key] = val - } - - return result -} diff --git a/buildpacks/java/java/func_yaml_envs.go b/buildpacks/java/java/func_yaml_envs.go new file mode 100644 index 00000000..552e1f59 --- /dev/null +++ b/buildpacks/java/java/func_yaml_envs.go @@ -0,0 +1,81 @@ +// Copyright 2021-2022 VMware, Inc. +// SPDX-License-Identifier: BSD-2-Clause + +package java + +import ( + "os" + "path/filepath" + + "github.com/buildpacks/libcnb" + "github.com/paketo-buildpacks/libpak" + "github.com/paketo-buildpacks/libpak/bard" + knfn "knative.dev/kn-plugin-func" +) + +type FuncYamlEnvs struct { + LayerContributor libpak.LayerContributor + Logger bard.Logger + + Envs map[string]string +} + +func NewFuncYamlEnvs(applicationPath string) FuncYamlEnvs { + envs := getFuncYamlEnvs(applicationPath) + return FuncYamlEnvs{ + LayerContributor: libpak.NewLayerContributor( + "func-yaml-envs", + envs, + libcnb.LayerTypes{ + Launch: true, + }, + ), + Envs: envs, + } +} + +func (f FuncYamlEnvs) Contribute(layer libcnb.Layer) (libcnb.Layer, error) { + f.LayerContributor.Logger = f.Logger + return f.LayerContributor.Contribute(layer, func() (libcnb.Layer, error) { + for k, v := range f.Envs { + layer.LaunchEnvironment.Default(k, v) + } + return layer, nil + }) +} + +func (f FuncYamlEnvs) Name() string { + return f.LayerContributor.Name +} + +func getFuncYamlEnvs(applicationPath string) map[string]string { + envs := map[string]string{} + + configFile := filepath.Join(applicationPath, knfn.ConfigFile) + _, err := os.Stat(configFile) + if err != nil { + return envs + } + + f, err := knfn.NewFunction(applicationPath) + if err != nil { + return envs + } + + return envsToMap(f.Envs) +} + +func envsToMap(envs knfn.Envs) map[string]string { + result := map[string]string{} + + for _, e := range envs { + key := *e.Name + val := "" + if e.Value != nil { + val = *e.Value + } + result[key] = val + } + + return result +} diff --git a/buildpacks/java/java/function.go b/buildpacks/java/java/function.go index 6df7f713..e828de66 100644 --- a/buildpacks/java/java/function.go +++ b/buildpacks/java/java/function.go @@ -4,8 +4,6 @@ package java import ( - "strings" - "github.com/buildpacks/libcnb" "github.com/paketo-buildpacks/libpak" "github.com/paketo-buildpacks/libpak/bard" @@ -15,24 +13,26 @@ type Function struct { LayerContributor libpak.LayerContributor Logger bard.Logger - ApplicationPath string - Handler string - Envs map[string]interface{} + ApplicationPath string + FunctionDefinition string + FunctionPackages string } -func NewFunction(plan libcnb.BuildpackPlanEntry, applicationPath string) Function { - envs := plan.Metadata["envs"].(map[string]interface{}) - +func NewFunction(packages string, definition string, applicationPath string) Function { return Function{ ApplicationPath: applicationPath, LayerContributor: libpak.NewLayerContributor( - plan.Name, - envs, + "java-function", + map[string]string{ + "packages": packages, + "definition": definition, + }, libcnb.LayerTypes{ Launch: true, }, ), - Envs: envs, + FunctionPackages: packages, + FunctionDefinition: definition, } } @@ -40,20 +40,21 @@ func (f Function) Contribute(layer libcnb.Layer) (libcnb.Layer, error) { f.LayerContributor.Logger = f.Logger return f.LayerContributor.Contribute(layer, func() (libcnb.Layer, error) { - if len(f.Handler) > 0 { - if strings.ContainsAny(f.Handler, ".") { - layer.LaunchEnvironment.Default("SPRING_CLOUD_FUNCTION_FUNCTION_CLASS", f.Handler) - } else { - layer.LaunchEnvironment.Default("SPRING_CLOUD_FUNCTION_DEFINITION", f.Handler) - } + if len(f.FunctionPackages) > 0 { + layer.LaunchEnvironment.Default("SPRING_CLOUD_FUNCTION_SCAN_PACKAGES", f.FunctionPackages) } - layer.LaunchEnvironment.Default("SPRING_CLOUD_FUNCTION_LOCATION", f.ApplicationPath) - - for k, v := range f.Envs { - layer.LaunchEnvironment.Default(k, v) + if len(f.FunctionDefinition) > 0 { + // if strings.ContainsAny(f.Handler, ".") { + // layer.LaunchEnvironment.Default("SPRING_CLOUD_FUNCTION_FUNCTION_CLASS", f.Handler) + // } else { + // layer.LaunchEnvironment.Default("SPRING_CLOUD_FUNCTION_DEFINITION", f.FunctionDefinition) + // } + layer.LaunchEnvironment.Default("SPRING_CLOUD_FUNCTION_DEFINITION", f.FunctionDefinition) } + layer.LaunchEnvironment.Default("SPRING_CLOUD_FUNCTION_LOCATION", f.ApplicationPath) + return layer, nil }) }