feat: validation for registry/namespace to not contain image name (#601)

* initial validation for registry/namespace to not contain image name

* Update function.go

* supporting nested namespace
This commit is contained in:
salaboy 2021-10-26 19:13:21 +01:00 committed by GitHub
parent 4bba2b48cb
commit cf9596c83e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 6 deletions

View File

@ -588,7 +588,7 @@ func (c *Client) Build(ctx context.Context, path string) (err error) {
return return
} }
// TODO: create a statu structure and return it here for optional // TODO: create a status structure and return it here for optional
// use by the cli for user echo (rather than rely on verbose mode here) // use by the cli for user echo (rather than rely on verbose mode here)
message := fmt.Sprintf("🙌 Function image built: %v", f.Image) message := fmt.Sprintf("🙌 Function image built: %v", f.Image)
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {

View File

@ -1,6 +1,7 @@
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
@ -83,6 +84,23 @@ kn func build --builder cnbs/sample-builder:bionic
return cmd return cmd
} }
func ValidNamespaceAndRegistry() survey.Validator {
return func(val interface{}) error {
// if the value passed in is the zero value of the appropriate type
if len(val.(string)) == 0 {
return errors.New("Value is required")
}
_, err := fn.DerivedImage("", val.(string)) //image can be derived without any error
if err != nil {
return errors.New(val.(string) + " Registry and Namespace are required (ie. docker.io/tigerteam). The image name will be derived from the function name.")
}
return nil
}
}
func runBuild(cmd *cobra.Command, _ []string, clientFn buildClientFn) (err error) { func runBuild(cmd *cobra.Command, _ []string, clientFn buildClientFn) (err error) {
config, err := newBuildConfig().Prompt() config, err := newBuildConfig().Prompt()
if err != nil { if err != nil {
@ -111,7 +129,7 @@ func runBuild(cmd *cobra.Command, _ []string, clientFn buildClientFn) (err error
err = survey.AskOne( err = survey.AskOne(
&survey.Input{Message: "Registry for Function images:"}, &survey.Input{Message: "Registry for Function images:"},
&config.Registry, survey.WithValidator(survey.Required)) &config.Registry, survey.WithValidator(ValidNamespaceAndRegistry()))
if err != nil { if err != nil {
if err == terminal.InterruptErr { if err == terminal.InterruptErr {
return nil return nil

View File

@ -156,7 +156,7 @@ func (f Function) ImageWithDigest() string {
// DerivedImage returns the derived image name (OCI container tag) of the // DerivedImage returns the derived image name (OCI container tag) of the
// Function whose source is at root, with the default registry for when // Function whose source is at root, with the default registry for when
// the image has to be calculated (derived). // the image has to be calculated (derived).
// The following are eqivalent due to the use of DefaultRegistry: // The following are equivalent due to the use of DefaultRegistry:
// registry: docker.io/myname // registry: docker.io/myname
// myname // myname
// A full image name consists of registry, image name and tag. // A full image name consists of registry, image name and tag.
@ -194,14 +194,20 @@ func DerivedImage(root, registry string) (image string, err error) {
// therefore derive the image tag from the defined registry and name. // therefore derive the image tag from the defined registry and name.
// form: [registry]/[user]/[function]:latest // form: [registry]/[user]/[function]:latest
// example: quay.io/alice/my.function.name:latest // example: quay.io/alice/my.function.name:latest
// Also nested namespaces should be supported:
// form: [registry]/[parent]/[user]/[function]:latest
// example: quay.io/project/alice/my.function.name:latest
registry = strings.Trim(registry, "/") // too defensive? registry = strings.Trim(registry, "/") // too defensive?
registryTokens := strings.Split(registry, "/") registryTokens := strings.Split(registry, "/")
if len(registryTokens) == 1 { if len(registryTokens) == 1 {
//namespace provided only 'alice'
image = DefaultRegistry + "/" + registry + "/" + f.Name image = DefaultRegistry + "/" + registry + "/" + f.Name
} else if len(registryTokens) == 2 { } else if len(registryTokens) == 2 || len(registryTokens) == 3 {
// registry/namespace provided `quay.io/alice` or registry/parent-namespace/namespace provided `quay.io/project/alice`
image = registry + "/" + f.Name image = registry + "/" + f.Name
} else { } else if len(registryTokens) > 3 { // the name of the image is also provided `quay.io/alice/my.function.name`
err = fmt.Errorf("registry should be either 'namespace' or 'registry/namespace'") err = fmt.Errorf("registry should be either 'namespace', 'registry/namespace' or 'registry/parent/namespace', the name of the image will be derived from the function name.")
return
} }
// Explicitly append :latest. We currently expect source control to drive // Explicitly append :latest. We currently expect source control to drive