Skip to content

Commit

Permalink
feat: ability for users to specify custom builders (knative#147)
Browse files Browse the repository at this point in the history
* refactor: functionWithOverrides
* feat: custom Buildpacks builder
* fix: namespaces
  • Loading branch information
matejvasek committed Oct 5, 2020
1 parent 5fe7052 commit c2b4a30
Show file tree
Hide file tree
Showing 13 changed files with 116 additions and 60 deletions.
4 changes: 4 additions & 0 deletions buildpacks/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ func (builder *Builder) Build(f faas.Function) (err error) {
var packBuilder string
if f.Builder != "" {
packBuilder = f.Builder
pb, ok := f.BuilderMap[packBuilder]
if ok {
packBuilder = pb
}
} else {
packBuilder = RuntimeToBuildpack[f.Runtime]
if packBuilder == "" {
Expand Down
1 change: 1 addition & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ func (c *Client) Initialize(cfg Function) (err error) {
if c.verbose {
fmt.Printf("Builder: %s\n", f.Builder)
}
f.BuilderMap = builders
}
// Remove the builders.yaml file so the user is not confused by a
// configuration file that is only used for project creation/initialization
Expand Down
16 changes: 14 additions & 2 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@ import (

func init() {
root.AddCommand(buildCmd)
buildCmd.Flags().StringP("builder", "b", "default", "Buildpacks builder")
buildCmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options - $FAAS_CONFIRM")
buildCmd.Flags().StringP("image", "i", "", "Optional full image name, in form [registry]/[namespace]/[name]:[tag] for example quay.io/myrepo/project.name:latest (overrides --repository) - $FAAS_IMAGE")
buildCmd.Flags().StringP("path", "p", cwd(), "Path to the Function project directory - $FAAS_PATH")
buildCmd.Flags().StringP("repository", "r", "", "Repository for built images, ex 'docker.io/myuser' or just 'myuser'. Optional if --image provided. - $FAAS_REPOSITORY")

err := buildCmd.RegisterFlagCompletionFunc("builder", CompleteBuilderList)
if err != nil {
fmt.Println("Error while calling RegisterFlagCompletionFunc: ", err)
}
}

var buildCmd = &cobra.Command{
Expand All @@ -33,15 +39,19 @@ name will be derived from the project name.
Any value provided for --image or --repository will be persisted in the
faas.yaml configuration file. On subsequent invocations of the "build" command
these values will be read from the configuration file.
It's possible to use a custom Buildpack builder with the --builder flag.
The value may be image name e.g. "cnbs/sample-builder:bionic",
or reference to builderMaps in the config file e.g. "default".
`,
SuggestFor: []string{"biuld", "buidl", "built"},
PreRunE: bindEnv("image", "path", "repository", "confirm"),
PreRunE: bindEnv("image", "path", "builder", "repository", "confirm"),
RunE: runBuild,
}

func runBuild(cmd *cobra.Command, _ []string) (err error) {
config := newBuildConfig()
function, err := functionWithOverrides(config.Path, "", config.Image)
function, err := functionWithOverrides(config.Path, functionOverrides{Builder: config.Builder, Image: config.Image})
if err != nil {
return
}
Expand Down Expand Up @@ -94,6 +104,7 @@ type buildConfig struct {
// Confirm: confirm values arrived upon from environment plus flags plus defaults,
// with interactive prompting (only applicable when attached to a TTY).
Confirm bool
Builder string
}

func newBuildConfig() buildConfig {
Expand All @@ -103,6 +114,7 @@ func newBuildConfig() buildConfig {
Repository: viper.GetString("repository"),
Verbose: viper.GetBool("verbose"), // defined on root
Confirm: viper.GetBool("confirm"),
Builder: viper.GetString("builder"),
}
}

Expand Down
29 changes: 29 additions & 0 deletions cmd/completion_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"encoding/json"
"github.com/boson-project/faas"
"os"
"os/user"
"path"
Expand Down Expand Up @@ -67,3 +68,31 @@ func CompleteRegistryList(cmd *cobra.Command, args []string, toComplete string)
directive = cobra.ShellCompDirectiveDefault
return
}

func CompleteBuilderList(cmd *cobra.Command, args []string, complete string) (strings []string, directive cobra.ShellCompDirective) {
directive = cobra.ShellCompDirectiveError

var (
err error
path string
f faas.Function
)

path, err = cmd.Flags().GetString("path")
if err != nil {
return
}

f, err = faas.NewFunction(path)
if err != nil {
return
}

strings = make([]string, 0, len(f.BuilderMap))
for name := range f.BuilderMap {
strings = append(strings, name)
}

directive = cobra.ShellCompDirectiveDefault
return
}
1 change: 1 addition & 0 deletions cmd/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func runDelete(cmd *cobra.Command, args []string) (err error) {

remover := knative.NewRemover(config.Namespace)
remover.Verbose = config.Verbose
remover.Namespace = config.Namespace

function := faas.Function{Root: config.Path, Name: config.Name}

Expand Down
3 changes: 2 additions & 1 deletion cmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ or -n flag, and if so this will overwrite the value in the faas.yaml file.

func runDeploy(cmd *cobra.Command, _ []string) (err error) {
config := newDeployConfig()
function, err := functionWithOverrides(config.Path, config.Namespace, "")
function, err := functionWithOverrides(config.Path, functionOverrides{Namespace: config.Namespace})
if err != nil {
return err
}
Expand All @@ -57,6 +57,7 @@ func runDeploy(cmd *cobra.Command, _ []string) (err error) {

deployer := knative.NewDeployer()
deployer.Verbose = config.Verbose
deployer.Namespace = function.Namespace

client := faas.New(
faas.WithVerbose(config.Verbose),
Expand Down
62 changes: 29 additions & 33 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,48 +120,44 @@ func bindEnv(flags ...string) bindFunc {
}
}

// overrideImage overwrites (or sets) the value of the Function's .Image
// property, which preempts the default functionality of deriving the value as:
// Deafult: [config.Repository]/[config.Name]:latest
func overrideImage(root, override string) (err error) {
if override == "" {
return
}
f, err := faas.NewFunction(root)
if err != nil {
return err
}
f.Image = override
return f.WriteConfig()
}

// overrideNamespace overwrites (or sets) the value of the Function's .Namespace
// property, which preempts the default functionality of using the underlying
// platform configuration (if supported). In the case of Kubernetes, this
// overrides the configured namespace (usually) set in ~/.kube.config.
func overrideNamespace(root, override string) (err error) {
if override == "" {
return
}
f, err := faas.NewFunction(root)
if err != nil {
return err
}
f.Namespace = override
return f.WriteConfig()
type functionOverrides struct {
Image string
Namespace string
Builder string
}

// functionWithOverrides sets the namespace and image strings for the
// Function project at root, if provided, and returns the Function
// configuration values
func functionWithOverrides(root, namespace, image string) (f faas.Function, err error) {
if err = overrideNamespace(root, namespace); err != nil {
func functionWithOverrides(root string, overrides functionOverrides) (f faas.Function, err error) {
f, err = faas.NewFunction(root)
if err != nil {
return
}
if err = overrideImage(root, image); err != nil {

overrideMapping := []struct{
src string
dest *string
} {
{overrides.Builder, &f.Builder},
{overrides.Image, &f.Image},
{overrides.Namespace, &f.Namespace},
}

for _, m := range overrideMapping {
if m.src != "" {
*m.dest = m.src
}
}

err = f.WriteConfig()
if err != nil {
return
}
return faas.NewFunction(root)

f, err = faas.NewFunction(root)
return

}

// deriveName returns the explicit value (if provided) or attempts to derive
Expand Down
2 changes: 1 addition & 1 deletion cmd/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ update is run, a new container image is always built.

func runUpdate(cmd *cobra.Command, args []string) (err error) {
config := newUpdateConfig()
function, err := functionWithOverrides(config.Path, config.Namespace, "")
function, err := functionWithOverrides(config.Path, functionOverrides{Namespace: config.Namespace})
if err != nil {
return err
}
Expand Down
39 changes: 21 additions & 18 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ const ConfigFile = "faas.yaml"
// Config represents the serialized state of a Function's metadata.
// See the Function struct for attribute documentation.
type config struct {
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`
Runtime string `yaml:"runtime"`
Image string `yaml:"image"`
Trigger string `yaml:"trigger"`
Builder string `yaml:"builder"`
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`
Runtime string `yaml:"runtime"`
Image string `yaml:"image"`
Trigger string `yaml:"trigger"`
Builder string `yaml:"builder"`
BuilderMap map[string]string `yaml:"builderMap"`
// Add new values to the toConfig/fromConfig functions.
}

Expand Down Expand Up @@ -49,24 +50,26 @@ func newConfig(root string) (c config, err error) {
// Note that config does not include ancillary fields not serialized, such as Root.
func fromConfig(c config) (f Function) {
return Function{
Name: c.Name,
Namespace: c.Namespace,
Runtime: c.Runtime,
Image: c.Image,
Trigger: c.Trigger,
Builder: c.Builder,
Name: c.Name,
Namespace: c.Namespace,
Runtime: c.Runtime,
Image: c.Image,
Trigger: c.Trigger,
Builder: c.Builder,
BuilderMap: c.BuilderMap,
}
}

// toConfig serializes a Function to a config object.
func toConfig(f Function) config {
return config{
Name: f.Name,
Namespace: f.Namespace,
Runtime: f.Runtime,
Image: f.Image,
Trigger: f.Trigger,
Builder: f.Builder,
Name: f.Name,
Namespace: f.Namespace,
Runtime: f.Runtime,
Image: f.Image,
Trigger: f.Trigger,
Builder: f.Builder,
BuilderMap: f.BuilderMap,
}
}

Expand Down
9 changes: 7 additions & 2 deletions function.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,13 @@ type Function struct {
// "Repo+Name:latest" to derive the Image.
Image string

// Builder represents the CNCF Buildpack builder image for a function
Builder string
// Builder represents the CNCF Buildpack builder image for a function,
// or it might be reference to `BuilderMap`.
Builder string

// Map containing known builders.
// e.g. { "jvm": "docker.io/example/quarkus-jvm-builder" }
BuilderMap map[string]string
}

// NewFunction loads a Function from a path on disk. use .Initialized() to determine if
Expand Down
2 changes: 1 addition & 1 deletion pkged.go

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion templates/quarkus/events/.builders.yaml
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
default: quay.io/boson/faas-quarkus-builder
default: quay.io/boson/faas-quarkus-jvm-builder
jvm: quay.io/boson/faas-quarkus-jvm-builder
native: quay.io/boson/faas-quarkus-native-builder
4 changes: 3 additions & 1 deletion templates/quarkus/http/.builders.yaml
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
default: quay.io/boson/faas-quarkus-builder
default: quay.io/boson/faas-quarkus-jvm-builder
jvm: quay.io/boson/faas-quarkus-jvm-builder
native: quay.io/boson/faas-quarkus-native-builder

0 comments on commit c2b4a30

Please sign in to comment.