From 3aca0edfcc7714d17d8881e9f5cde2f6156cc718 Mon Sep 17 00:00:00 2001 From: Ta-Ching Chen Date: Mon, 18 Nov 2019 13:46:28 +0800 Subject: [PATCH] Show warning when referencing nonexistent resources in spec (#1415) --- pkg/fission-cli/cmd/function/create.go | 86 +++++++++++++++-------- pkg/fission-cli/cmd/httptrigger/create.go | 23 +++++- pkg/fission-cli/cmd/kubewatch/create.go | 22 ++++++ pkg/fission-cli/cmd/mqtrigger/create.go | 22 ++++++ pkg/fission-cli/cmd/package/create.go | 20 ++++++ pkg/fission-cli/cmd/spec/spec.go | 4 +- pkg/fission-cli/cmd/timetrigger/create.go | 23 ++++++ 7 files changed, 166 insertions(+), 34 deletions(-) diff --git a/pkg/fission-cli/cmd/function/create.go b/pkg/fission-cli/cmd/function/create.go index 3f368920..1d91fa79 100644 --- a/pkg/fission-cli/cmd/function/create.go +++ b/pkg/fission-cli/cmd/function/create.go @@ -82,15 +82,17 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { } specDir := util.GetSpecDir(input) - // check for unique function names within a namespace - fn, err := opts.client.FunctionGet(&metav1.ObjectMeta{ - Name: input.String(flagkey.FnName), - Namespace: input.String(flagkey.NamespaceFunction), - }) - if err != nil && !ferror.IsNotFound(err) { - return err - } else if fn != nil { - return errors.New("a function with the same name already exists") + if !toSpec { + // check for unique function names within a namespace + fn, err := opts.client.FunctionGet(&metav1.ObjectMeta{ + Name: input.String(flagkey.FnName), + Namespace: input.String(flagkey.NamespaceFunction), + }) + if err != nil && !ferror.IsNotFound(err) { + return err + } else if fn != nil { + return errors.New("a function with the same name already exists") + } } entrypoint := input.String(flagkey.FnEntrypoint) @@ -160,8 +162,26 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { return errors.New("need --env argument") } - // examine existence of given environment. If specs - then spec validate will do it, don't check here. - if !toSpec { + if toSpec { + specDir := util.GetSpecDir(input) + fr, err := spec.ReadSpecs(specDir) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("error reading spec in '%v'", specDir)) + } + exists, err := fr.ExistsInSpecs(fv1.Environment{ + Metadata: metav1.ObjectMeta{ + Name: envName, + Namespace: envNamespace, + }, + }) + if err != nil { + return err + } + if !exists { + console.Warn(fmt.Sprintf("Function '%v' references unknown Environment '%v', please create it before applying spec", + fnName, envName)) + } + } else { _, err := opts.client.EnvironmentGet(&metav1.ObjectMeta{ Namespace: envNamespace, Name: envName, @@ -206,16 +226,18 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { if len(secretNames) > 0 { // check the referenced secret is in the same ns as the function, if not give a warning. - for _, secretName := range secretNames { - _, err := opts.client.SecretGet(&metav1.ObjectMeta{ - Namespace: fnNamespace, - Name: secretName, - }) - if err != nil { - if k8serrors.IsNotFound(err) { - console.Warn(fmt.Sprintf("Secret %s not found in Namespace: %s. Secret needs to be present in the same namespace as function", secretName, fnNamespace)) - } else { - return errors.Wrap(err, "error checking secret") + if !toSpec { // TODO: workaround in order not to block users from creating function spec, remove it. + for _, secretName := range secretNames { + _, err := opts.client.SecretGet(&metav1.ObjectMeta{ + Namespace: fnNamespace, + Name: secretName, + }) + if err != nil { + if k8serrors.IsNotFound(err) { + console.Warn(fmt.Sprintf("Secret %s not found in Namespace: %s. Secret needs to be present in the same namespace as function", secretName, fnNamespace)) + } else { + return errors.Wrap(err, "error checking secret") + } } } } @@ -230,16 +252,18 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { if len(cfgMapNames) > 0 { // check the referenced cfgmap is in the same ns as the function, if not give a warning. - for _, cfgMapName := range cfgMapNames { - _, err := opts.client.ConfigMapGet(&metav1.ObjectMeta{ - Namespace: fnNamespace, - Name: cfgMapName, - }) - if err != nil { - if k8serrors.IsNotFound(err) { - console.Warn(fmt.Sprintf("ConfigMap %s not found in Namespace: %s. ConfigMap needs to be present in the same namespace as function", cfgMapName, fnNamespace)) - } else { - return errors.Wrap(err, "error checking configmap") + if !toSpec { + for _, cfgMapName := range cfgMapNames { + _, err := opts.client.ConfigMapGet(&metav1.ObjectMeta{ + Namespace: fnNamespace, + Name: cfgMapName, + }) + if err != nil { + if k8serrors.IsNotFound(err) { + console.Warn(fmt.Sprintf("ConfigMap %s not found in Namespace: %s. ConfigMap needs to be present in the same namespace as function", cfgMapName, fnNamespace)) + } else { + return errors.Wrap(err, "error checking configmap") + } } } } diff --git a/pkg/fission-cli/cmd/httptrigger/create.go b/pkg/fission-cli/cmd/httptrigger/create.go index 3a669ab7..56081e3e 100644 --- a/pkg/fission-cli/cmd/httptrigger/create.go +++ b/pkg/fission-cli/cmd/httptrigger/create.go @@ -106,7 +106,28 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { } // For Specs, the spec validate checks for function reference - if !input.Bool(flagkey.SpecSave) { + if input.Bool(flagkey.SpecSave) { + specDir := util.GetSpecDir(input) + fr, err := spec.ReadSpecs(specDir) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("error reading spec in '%v'", specDir)) + } + for _, fn := range functionList { + exists, err := fr.ExistsInSpecs(fv1.Function{ + Metadata: metav1.ObjectMeta{ + Name: fn, + Namespace: fnNamespace, + }, + }) + if err != nil { + return err + } + if !exists { + console.Warn(fmt.Sprintf("HTTPTrigger '%v' references unknown Function '%v', please create it before applying spec", + triggerName, fn)) + } + } + } else { err = util.CheckFunctionExistence(opts.client, functionList, fnNamespace) if err != nil { console.Warn(err.Error()) diff --git a/pkg/fission-cli/cmd/kubewatch/create.go b/pkg/fission-cli/cmd/kubewatch/create.go index ae82182e..802b286b 100644 --- a/pkg/fission-cli/cmd/kubewatch/create.go +++ b/pkg/fission-cli/cmd/kubewatch/create.go @@ -67,6 +67,28 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { namespace := input.String(flagkey.KwNamespace) objType := input.String(flagkey.KwObjType) + if input.Bool(flagkey.SpecSave) { + specDir := util.GetSpecDir(input) + fr, err := spec.ReadSpecs(specDir) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("error reading spec in '%v'", specDir)) + } + + exists, err := fr.ExistsInSpecs(fv1.Function{ + Metadata: metav1.ObjectMeta{ + Name: fnName, + Namespace: fnNamespace, + }, + }) + if err != nil { + return err + } + if !exists { + console.Warn(fmt.Sprintf("KubernetesWatchTrigger '%v' references unknown Function '%v', please create it before applying spec", + watchName, fnName)) + } + } + opts.watcher = &fv1.KubernetesWatchTrigger{ Metadata: metav1.ObjectMeta{ Name: watchName, diff --git a/pkg/fission-cli/cmd/mqtrigger/create.go b/pkg/fission-cli/cmd/mqtrigger/create.go index cbd65deb..11c90db3 100644 --- a/pkg/fission-cli/cmd/mqtrigger/create.go +++ b/pkg/fission-cli/cmd/mqtrigger/create.go @@ -109,6 +109,28 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { return err } + if input.Bool(flagkey.SpecSave) { + specDir := util.GetSpecDir(input) + fr, err := spec.ReadSpecs(specDir) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("error reading spec in '%v'", specDir)) + } + + exists, err := fr.ExistsInSpecs(fv1.Function{ + Metadata: metav1.ObjectMeta{ + Name: fnName, + Namespace: fnNamespace, + }, + }) + if err != nil { + return err + } + if !exists { + console.Warn(fmt.Sprintf("MessageQueueTrigger '%v' references unknown Function '%v', please create it before applying spec", + mqtName, fnName)) + } + } + opts.trigger = &fv1.MessageQueueTrigger{ Metadata: metav1.ObjectMeta{ Name: mqtName, diff --git a/pkg/fission-cli/cmd/package/create.go b/pkg/fission-cli/cmd/package/create.go index a3698dda..dd137ef9 100644 --- a/pkg/fission-cli/cmd/package/create.go +++ b/pkg/fission-cli/cmd/package/create.go @@ -89,7 +89,27 @@ func (opts *CreateSubCommand) run(input cli.Input) error { } var specDir, specFile string + if input.Bool(flagkey.SpecSave) { + specDir = util.GetSpecDir(input) + fr, err := spec.ReadSpecs(specDir) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("error reading spec in '%v'", specDir)) + } + exists, err := fr.ExistsInSpecs(fv1.Environment{ + Metadata: metav1.ObjectMeta{ + Name: envName, + Namespace: envNamespace, + }, + }) + if err != nil { + return err + } + if !exists { + console.Warn(fmt.Sprintf("Package '%v' references unknown Environment '%v', please create it before applying spec", + pkgName, envName)) + } + specDir = util.GetSpecDir(input) specFile = fmt.Sprintf("package-%v.yaml", pkgName) } diff --git a/pkg/fission-cli/cmd/spec/spec.go b/pkg/fission-cli/cmd/spec/spec.go index 9ddb3840..35ef71cc 100644 --- a/pkg/fission-cli/cmd/spec/spec.go +++ b/pkg/fission-cli/cmd/spec/spec.go @@ -233,7 +233,7 @@ func SpecSave(resource interface{}, specFile string) error { return errors.Wrap(err, fmt.Sprintf("error reading spec in '%v'", specDir)) } - exists, err := fr.existsInSpecs(resource) + exists, err := fr.ExistsInSpecs(resource) if err != nil { return err } @@ -664,7 +664,7 @@ func (fr *FissionResources) SpecExists(resource interface{}, compareMetadata boo } } -func (fr *FissionResources) existsInSpecs(resource interface{}) (bool, error) { +func (fr *FissionResources) ExistsInSpecs(resource interface{}) (bool, error) { switch typedres := resource.(type) { case types.ArchiveUploadSpec: for _, obj := range fr.ArchiveUploadSpecs { diff --git a/pkg/fission-cli/cmd/timetrigger/create.go b/pkg/fission-cli/cmd/timetrigger/create.go index 20d33688..019b4f8f 100644 --- a/pkg/fission-cli/cmd/timetrigger/create.go +++ b/pkg/fission-cli/cmd/timetrigger/create.go @@ -29,6 +29,7 @@ import ( "github.com/fission/fission/pkg/controller/client" "github.com/fission/fission/pkg/fission-cli/cliwrapper/cli" "github.com/fission/fission/pkg/fission-cli/cmd/spec" + "github.com/fission/fission/pkg/fission-cli/console" flagkey "github.com/fission/fission/pkg/fission-cli/flag/key" "github.com/fission/fission/pkg/fission-cli/util" ) @@ -75,6 +76,28 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { return errors.New("Need a cron spec like '0 30 * * * *', '@every 1h30m', or '@hourly'; use --cron") } + if input.Bool(flagkey.SpecSave) { + specDir := util.GetSpecDir(input) + fr, err := spec.ReadSpecs(specDir) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("error reading spec in '%v'", specDir)) + } + + exists, err := fr.ExistsInSpecs(fv1.Function{ + Metadata: metav1.ObjectMeta{ + Name: fnName, + Namespace: fnNamespace, + }, + }) + if err != nil { + return err + } + if !exists { + console.Warn(fmt.Sprintf("TimeTrigger '%v' references unknown Function '%v', please create it before applying spec", + name, fnName)) + } + } + opts.trigger = &fv1.TimeTrigger{ Metadata: metav1.ObjectMeta{ Name: name,