mirror of https://github.com/knative/func.git
feat: ability for users to specify custom builders (#147)
* refactor: functionWithOverrides * feat: custom Buildpacks builder * fix: namespaces
This commit is contained in:
parent
5fe70526e5
commit
c2b4a304bd
|
@ -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 == "" {
|
||||
|
|
|
@ -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
|
||||
|
|
16
cmd/build.go
16
cmd/build.go
|
@ -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{
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package cmd
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/boson-project/faas"
|
||||
"os"
|
||||
"os/user"
|
||||
"path"
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
@ -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),
|
||||
|
|
62
cmd/root.go
62
cmd/root.go
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
39
config.go
39
config.go
|
@ -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.
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue