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