Skip to content
This repository has been archived by the owner on Oct 25, 2023. It is now read-only.

Commit

Permalink
feat: Add configuration for Java buildpack
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
andrew-su committed May 31, 2022
1 parent 0fccc84 commit 8b7067d
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 58 deletions.
14 changes: 12 additions & 2 deletions buildpacks/java/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,28 @@ The Java Function Buildpack is a Cloud Native Buildpack that provides a Spring B

## Behaviour
This buildpack will participate if any of the following conditions are met:
* A file with the name `func.yaml` is detected
* One of the configuration environment variables are explicitly set.
* A file with the name `func.yaml` is detected.

The buildpack will do the following if detection passed:
* Request for a JRE to be installed
* Contributes the Spring Boot application to a layer marked `launch` with the layer's path prepended to `$CLASSPATH`
* Contributes environment variables defined in `func.yaml` to the `launch` layer
* Contributes environment variables to configure Spring Boot if any configuration variables are defined. (Overrides anything from `func.yaml`)

## Configuration

| Environment Variable | Description |
|----------------------|-------------|
| `$BP_FUNCTION` | Configure the composition of functions. Defaults to empty (load all functions). |
| `$BP_FUNCTION_PACKAGES` | Configure the package to search for functions. Defaults to `functions`. |


## Getting started
To get started you'll need to create a directory where your function will be defined.

From within this directory we require a few files to properly detect this as a Java function:
* `func.yaml`: We use this to configure the runtime environment variables. See the [Knative Func CLI docs](https://github.com/knative-sandbox/kn-plugin-func/blob/main/docs/guides/func_yaml.md) for more details.
* `func.yaml` (optional): We use this to configure the runtime environment variables. See the [Knative Func CLI docs](https://github.com/knative-sandbox/kn-plugin-func/blob/main/docs/guides/func_yaml.md) for more details.
* `pom.xml` or `build.gradle`: These are used by the other Java buildpacks to compile your function.
* Java package in folder `src/main/java/functions`: This is the default location your function will be detected. If you do choose to use another package to store your functions, you will need to [set a new search location](#TODO).

Expand Down
12 changes: 12 additions & 0 deletions buildpacks/java/buildpack.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
15 changes: 10 additions & 5 deletions buildpacks/java/java/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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 {
Expand All @@ -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)

Expand Down
65 changes: 35 additions & 30 deletions buildpacks/java/java/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -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{
Expand All @@ -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,
},
},
{
Expand All @@ -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
}
81 changes: 81 additions & 0 deletions buildpacks/java/java/func_yaml_envs.go
Original file line number Diff line number Diff line change
@@ -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
}
43 changes: 22 additions & 21 deletions buildpacks/java/java/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
package java

import (
"strings"

"github.com/buildpacks/libcnb"
"github.com/paketo-buildpacks/libpak"
"github.com/paketo-buildpacks/libpak/bard"
Expand All @@ -15,45 +13,48 @@ 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,
}
}

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
})
}
Expand Down

0 comments on commit 8b7067d

Please sign in to comment.