Skip to content

Commit c2b4a30

Browse files
authored
feat: ability for users to specify custom builders (#147)
* refactor: functionWithOverrides * feat: custom Buildpacks builder * fix: namespaces
1 parent 5fe7052 commit c2b4a30

13 files changed

+116
-60
lines changed

buildpacks/builder.go

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ func (builder *Builder) Build(f faas.Function) (err error) {
3636
var packBuilder string
3737
if f.Builder != "" {
3838
packBuilder = f.Builder
39+
pb, ok := f.BuilderMap[packBuilder]
40+
if ok {
41+
packBuilder = pb
42+
}
3943
} else {
4044
packBuilder = RuntimeToBuildpack[f.Runtime]
4145
if packBuilder == "" {

client.go

+1
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ func (c *Client) Initialize(cfg Function) (err error) {
360360
if c.verbose {
361361
fmt.Printf("Builder: %s\n", f.Builder)
362362
}
363+
f.BuilderMap = builders
363364
}
364365
// Remove the builders.yaml file so the user is not confused by a
365366
// configuration file that is only used for project creation/initialization

cmd/build.go

+14-2
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,16 @@ import (
1313

1414
func init() {
1515
root.AddCommand(buildCmd)
16+
buildCmd.Flags().StringP("builder", "b", "default", "Buildpacks builder")
1617
buildCmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options - $FAAS_CONFIRM")
1718
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")
1819
buildCmd.Flags().StringP("path", "p", cwd(), "Path to the Function project directory - $FAAS_PATH")
1920
buildCmd.Flags().StringP("repository", "r", "", "Repository for built images, ex 'docker.io/myuser' or just 'myuser'. Optional if --image provided. - $FAAS_REPOSITORY")
21+
22+
err := buildCmd.RegisterFlagCompletionFunc("builder", CompleteBuilderList)
23+
if err != nil {
24+
fmt.Println("Error while calling RegisterFlagCompletionFunc: ", err)
25+
}
2026
}
2127

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

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

99110
func newBuildConfig() buildConfig {
@@ -103,6 +114,7 @@ func newBuildConfig() buildConfig {
103114
Repository: viper.GetString("repository"),
104115
Verbose: viper.GetBool("verbose"), // defined on root
105116
Confirm: viper.GetBool("confirm"),
117+
Builder: viper.GetString("builder"),
106118
}
107119
}
108120

cmd/completion_util.go

+29
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cmd
22

33
import (
44
"encoding/json"
5+
"github.com/boson-project/faas"
56
"os"
67
"os/user"
78
"path"
@@ -67,3 +68,31 @@ func CompleteRegistryList(cmd *cobra.Command, args []string, toComplete string)
6768
directive = cobra.ShellCompDirectiveDefault
6869
return
6970
}
71+
72+
func CompleteBuilderList(cmd *cobra.Command, args []string, complete string) (strings []string, directive cobra.ShellCompDirective) {
73+
directive = cobra.ShellCompDirectiveError
74+
75+
var (
76+
err error
77+
path string
78+
f faas.Function
79+
)
80+
81+
path, err = cmd.Flags().GetString("path")
82+
if err != nil {
83+
return
84+
}
85+
86+
f, err = faas.NewFunction(path)
87+
if err != nil {
88+
return
89+
}
90+
91+
strings = make([]string, 0, len(f.BuilderMap))
92+
for name := range f.BuilderMap {
93+
strings = append(strings, name)
94+
}
95+
96+
directive = cobra.ShellCompDirectiveDefault
97+
return
98+
}

cmd/delete.go

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func runDelete(cmd *cobra.Command, args []string) (err error) {
4242

4343
remover := knative.NewRemover(config.Namespace)
4444
remover.Verbose = config.Verbose
45+
remover.Namespace = config.Namespace
4546

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

cmd/deploy.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ or -n flag, and if so this will overwrite the value in the faas.yaml file.
4141

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

5858
deployer := knative.NewDeployer()
5959
deployer.Verbose = config.Verbose
60+
deployer.Namespace = function.Namespace
6061

6162
client := faas.New(
6263
faas.WithVerbose(config.Verbose),

cmd/root.go

+29-33
Original file line numberDiff line numberDiff line change
@@ -120,48 +120,44 @@ func bindEnv(flags ...string) bindFunc {
120120
}
121121
}
122122

123-
// overrideImage overwrites (or sets) the value of the Function's .Image
124-
// property, which preempts the default functionality of deriving the value as:
125-
// Deafult: [config.Repository]/[config.Name]:latest
126-
func overrideImage(root, override string) (err error) {
127-
if override == "" {
128-
return
129-
}
130-
f, err := faas.NewFunction(root)
131-
if err != nil {
132-
return err
133-
}
134-
f.Image = override
135-
return f.WriteConfig()
136-
}
137-
138-
// overrideNamespace overwrites (or sets) the value of the Function's .Namespace
139-
// property, which preempts the default functionality of using the underlying
140-
// platform configuration (if supported). In the case of Kubernetes, this
141-
// overrides the configured namespace (usually) set in ~/.kube.config.
142-
func overrideNamespace(root, override string) (err error) {
143-
if override == "" {
144-
return
145-
}
146-
f, err := faas.NewFunction(root)
147-
if err != nil {
148-
return err
149-
}
150-
f.Namespace = override
151-
return f.WriteConfig()
123+
type functionOverrides struct {
124+
Image string
125+
Namespace string
126+
Builder string
152127
}
153128

154129
// functionWithOverrides sets the namespace and image strings for the
155130
// Function project at root, if provided, and returns the Function
156131
// configuration values
157-
func functionWithOverrides(root, namespace, image string) (f faas.Function, err error) {
158-
if err = overrideNamespace(root, namespace); err != nil {
132+
func functionWithOverrides(root string, overrides functionOverrides) (f faas.Function, err error) {
133+
f, err = faas.NewFunction(root)
134+
if err != nil {
159135
return
160136
}
161-
if err = overrideImage(root, image); err != nil {
137+
138+
overrideMapping := []struct{
139+
src string
140+
dest *string
141+
} {
142+
{overrides.Builder, &f.Builder},
143+
{overrides.Image, &f.Image},
144+
{overrides.Namespace, &f.Namespace},
145+
}
146+
147+
for _, m := range overrideMapping {
148+
if m.src != "" {
149+
*m.dest = m.src
150+
}
151+
}
152+
153+
err = f.WriteConfig()
154+
if err != nil {
162155
return
163156
}
164-
return faas.NewFunction(root)
157+
158+
f, err = faas.NewFunction(root)
159+
return
160+
165161
}
166162

167163
// deriveName returns the explicit value (if provided) or attempts to derive

cmd/update.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ update is run, a new container image is always built.
5050

5151
func runUpdate(cmd *cobra.Command, args []string) (err error) {
5252
config := newUpdateConfig()
53-
function, err := functionWithOverrides(config.Path, config.Namespace, "")
53+
function, err := functionWithOverrides(config.Path, functionOverrides{Namespace: config.Namespace})
5454
if err != nil {
5555
return err
5656
}

config.go

+21-18
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ const ConfigFile = "faas.yaml"
1414
// Config represents the serialized state of a Function's metadata.
1515
// See the Function struct for attribute documentation.
1616
type config struct {
17-
Name string `yaml:"name"`
18-
Namespace string `yaml:"namespace"`
19-
Runtime string `yaml:"runtime"`
20-
Image string `yaml:"image"`
21-
Trigger string `yaml:"trigger"`
22-
Builder string `yaml:"builder"`
17+
Name string `yaml:"name"`
18+
Namespace string `yaml:"namespace"`
19+
Runtime string `yaml:"runtime"`
20+
Image string `yaml:"image"`
21+
Trigger string `yaml:"trigger"`
22+
Builder string `yaml:"builder"`
23+
BuilderMap map[string]string `yaml:"builderMap"`
2324
// Add new values to the toConfig/fromConfig functions.
2425
}
2526

@@ -49,24 +50,26 @@ func newConfig(root string) (c config, err error) {
4950
// Note that config does not include ancillary fields not serialized, such as Root.
5051
func fromConfig(c config) (f Function) {
5152
return Function{
52-
Name: c.Name,
53-
Namespace: c.Namespace,
54-
Runtime: c.Runtime,
55-
Image: c.Image,
56-
Trigger: c.Trigger,
57-
Builder: c.Builder,
53+
Name: c.Name,
54+
Namespace: c.Namespace,
55+
Runtime: c.Runtime,
56+
Image: c.Image,
57+
Trigger: c.Trigger,
58+
Builder: c.Builder,
59+
BuilderMap: c.BuilderMap,
5860
}
5961
}
6062

6163
// toConfig serializes a Function to a config object.
6264
func toConfig(f Function) config {
6365
return config{
64-
Name: f.Name,
65-
Namespace: f.Namespace,
66-
Runtime: f.Runtime,
67-
Image: f.Image,
68-
Trigger: f.Trigger,
69-
Builder: f.Builder,
66+
Name: f.Name,
67+
Namespace: f.Namespace,
68+
Runtime: f.Runtime,
69+
Image: f.Image,
70+
Trigger: f.Trigger,
71+
Builder: f.Builder,
72+
BuilderMap: f.BuilderMap,
7073
}
7174
}
7275

function.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,13 @@ type Function struct {
4141
// "Repo+Name:latest" to derive the Image.
4242
Image string
4343

44-
// Builder represents the CNCF Buildpack builder image for a function
45-
Builder string
44+
// Builder represents the CNCF Buildpack builder image for a function,
45+
// or it might be reference to `BuilderMap`.
46+
Builder string
47+
48+
// Map containing known builders.
49+
// e.g. { "jvm": "docker.io/example/quarkus-jvm-builder" }
50+
BuilderMap map[string]string
4651
}
4752

4853
// NewFunction loads a Function from a path on disk. use .Initialized() to determine if

pkged.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+3-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
default: quay.io/boson/faas-quarkus-builder
1+
default: quay.io/boson/faas-quarkus-jvm-builder
2+
jvm: quay.io/boson/faas-quarkus-jvm-builder
3+
native: quay.io/boson/faas-quarkus-native-builder

templates/quarkus/http/.builders.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
default: quay.io/boson/faas-quarkus-builder
1+
default: quay.io/boson/faas-quarkus-jvm-builder
2+
jvm: quay.io/boson/faas-quarkus-jvm-builder
3+
native: quay.io/boson/faas-quarkus-native-builder

0 commit comments

Comments
 (0)