diff --git a/pkg/fission-cli/cmd/environment/command.go b/pkg/fission-cli/cmd/environment/command.go index 9703405f..58383b8a 100644 --- a/pkg/fission-cli/cmd/environment/command.go +++ b/pkg/fission-cli/cmd/environment/command.go @@ -34,7 +34,7 @@ func Commands() *cobra.Command { Optional: []flag.Flag{flag.EnvPoolsize, flag.EnvBuilderImage, flag.EnvBuildCmd, flag.RunTimeMinCPU, flag.RunTimeMaxCPU, flag.RunTimeMinMemory, flag.RunTimeMaxMemory, flag.EnvTerminationGracePeriod, flag.EnvVersion, flag.EnvImagePullSecret, - flag.EnvExternalNetwork, flag.EnvKeepArchive, flag.NamespaceEnvironment, flag.SpecSave}, + flag.EnvExternalNetwork, flag.EnvKeepArchive, flag.NamespaceEnvironment, flag.SpecSave, flag.SpecDry}, }) getCmd := &cobra.Command{ diff --git a/pkg/fission-cli/cmd/environment/create.go b/pkg/fission-cli/cmd/environment/create.go index d14781c4..dd45f00f 100644 --- a/pkg/fission-cli/cmd/environment/create.go +++ b/pkg/fission-cli/cmd/environment/create.go @@ -75,12 +75,16 @@ func (opts *CreateSubCommand) run(input cli.Input) error { } // if we're writing a spec, don't call the API - // save to spec file + // save to spec file or display the spec to console + if input.Bool(flagkey.SpecDry) { + return spec.SpecDry(*opts.env) + } + if input.Bool(flagkey.SpecSave) { specFile := fmt.Sprintf("env-%v.yaml", m.Name) err = spec.SpecSave(*opts.env, specFile) if err != nil { - return errors.Wrap(err, "error creating environment spec") + return errors.Wrap(err, "error saving environment spec") } return nil } diff --git a/pkg/fission-cli/cmd/function/command.go b/pkg/fission-cli/cmd/function/command.go index 59dcc615..d1eae15a 100644 --- a/pkg/fission-cli/cmd/function/command.go +++ b/pkg/fission-cli/cmd/function/command.go @@ -48,7 +48,7 @@ func Commands() *cobra.Command { flag.RunTimeMaxMemory, flag.ReplicasMin, flag.ReplicasMax, flag.RunTimeTargetCPU, - flag.NamespaceFunction, flag.NamespaceEnvironment, flag.SpecSave}, + flag.NamespaceFunction, flag.NamespaceEnvironment, flag.SpecSave, flag.SpecDry}, }) getCmd := &cobra.Command{ diff --git a/pkg/fission-cli/cmd/function/create.go b/pkg/fission-cli/cmd/function/create.go index d10da43b..6f5265ba 100644 --- a/pkg/fission-cli/cmd/function/create.go +++ b/pkg/fission-cli/cmd/function/create.go @@ -301,10 +301,15 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { // It also prints warning/error if necessary. func (opts *CreateSubCommand) run(input cli.Input) error { // if we're writing a spec, don't create the function + // save to spec file or display the spec to console + if input.Bool(flagkey.SpecDry) { + return spec.SpecDry(*opts.function) + } + if input.Bool(flagkey.SpecSave) { err := spec.SpecSave(*opts.function, opts.specFile) if err != nil { - return errors.Wrap(err, "error creating function spec") + return errors.Wrap(err, "error saving function spec") } return nil } diff --git a/pkg/fission-cli/cmd/httptrigger/command.go b/pkg/fission-cli/cmd/httptrigger/command.go index 1dffcf85..cdefeb44 100644 --- a/pkg/fission-cli/cmd/httptrigger/command.go +++ b/pkg/fission-cli/cmd/httptrigger/command.go @@ -33,7 +33,7 @@ func Commands() *cobra.Command { Required: []flag.Flag{flag.HtUrl, flag.HtFnName}, Optional: []flag.Flag{flag.HtName, flag.HtMethod, flag.HtIngress, flag.HtIngressRule, flag.HtIngressAnnotation, flag.HtIngressTLS, - flag.HtFnWeight, flag.HtHost, flag.NamespaceFunction, flag.SpecSave}, + flag.HtFnWeight, flag.HtHost, flag.NamespaceFunction, flag.SpecSave, flag.SpecDry}, }) getCmd := &cobra.Command{ diff --git a/pkg/fission-cli/cmd/httptrigger/create.go b/pkg/fission-cli/cmd/httptrigger/create.go index 304f51fd..98bd991b 100644 --- a/pkg/fission-cli/cmd/httptrigger/create.go +++ b/pkg/fission-cli/cmd/httptrigger/create.go @@ -22,7 +22,7 @@ import ( "strings" "github.com/pkg/errors" - "github.com/satori/go.uuid" + uuid "github.com/satori/go.uuid" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" fv1 "github.com/fission/fission/pkg/apis/core/v1" @@ -157,11 +157,16 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { func (opts *CreateSubCommand) run(input cli.Input) error { // if we're writing a spec, don't call the API + // save to spec file or display the spec to console + if input.Bool(flagkey.SpecDry) { + return spec.SpecDry(*opts.trigger) + } + if input.Bool(flagkey.SpecSave) { specFile := fmt.Sprintf("route-%v.yaml", opts.trigger.ObjectMeta.Name) err := spec.SpecSave(*opts.trigger, specFile) if err != nil { - return errors.Wrap(err, "error creating HTTP trigger spec") + return errors.Wrap(err, "error saving HTTP trigger spec") } return nil } diff --git a/pkg/fission-cli/cmd/kubewatch/command.go b/pkg/fission-cli/cmd/kubewatch/command.go index 5696ef80..fe5e3438 100644 --- a/pkg/fission-cli/cmd/kubewatch/command.go +++ b/pkg/fission-cli/cmd/kubewatch/command.go @@ -31,7 +31,7 @@ func Commands() *cobra.Command { } wrapper.SetFlags(createCmd, flag.FlagSet{ Required: []flag.Flag{flag.KwFnName}, - Optional: []flag.Flag{flag.KwName, flag.KwObjType, flag.KwNamespace, flag.NamespaceFunction, flag.SpecSave}, + Optional: []flag.Flag{flag.KwName, flag.KwObjType, flag.KwNamespace, flag.NamespaceFunction, flag.SpecSave, flag.SpecDry}, // TODO: add label selector flag // flag.KwLabelsFlag }) diff --git a/pkg/fission-cli/cmd/kubewatch/create.go b/pkg/fission-cli/cmd/kubewatch/create.go index 8b8e9032..9a656aaa 100644 --- a/pkg/fission-cli/cmd/kubewatch/create.go +++ b/pkg/fission-cli/cmd/kubewatch/create.go @@ -103,11 +103,16 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { func (opts *CreateSubCommand) run(input cli.Input) error { // if we're writing a spec, don't call the API + // save to spec file or display the spec to console + if input.Bool(flagkey.SpecDry) { + return spec.SpecDry(*opts.watcher) + } + if input.Bool(flagkey.SpecSave) { specFile := fmt.Sprintf("kubewatch-%v.yaml", opts.watcher.ObjectMeta.Name) err := spec.SpecSave(*opts.watcher, specFile) if err != nil { - return errors.Wrap(err, "error creating kubewatch spec") + return errors.Wrap(err, "error saving kubewatch spec") } return nil } diff --git a/pkg/fission-cli/cmd/mqtrigger/command.go b/pkg/fission-cli/cmd/mqtrigger/command.go index 782dff30..ef5c3616 100644 --- a/pkg/fission-cli/cmd/mqtrigger/command.go +++ b/pkg/fission-cli/cmd/mqtrigger/command.go @@ -33,7 +33,7 @@ func Commands() *cobra.Command { Required: []flag.Flag{flag.MqtFnName, flag.MqtTopic}, Optional: []flag.Flag{flag.MqtName, flag.MqtMQType, flag.MqtRespTopic, flag.MqtErrorTopic, flag.MqtMaxRetries, flag.MqtMsgContentType, - flag.NamespaceFunction, flag.SpecSave}, + flag.NamespaceFunction, flag.SpecSave, flag.SpecDry}, }) updateCmd := &cobra.Command{ diff --git a/pkg/fission-cli/cmd/mqtrigger/create.go b/pkg/fission-cli/cmd/mqtrigger/create.go index 136bd78a..ef5a64f3 100644 --- a/pkg/fission-cli/cmd/mqtrigger/create.go +++ b/pkg/fission-cli/cmd/mqtrigger/create.go @@ -147,11 +147,16 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { func (opts *CreateSubCommand) run(input cli.Input) error { // if we're writing a spec, don't call the API + // save to spec file or display the spec to console + if input.Bool(flagkey.SpecDry) { + return spec.SpecDry(*opts.trigger) + } + if input.Bool(flagkey.SpecSave) { specFile := fmt.Sprintf("mqtrigger-%v.yaml", opts.trigger.ObjectMeta.Name) err := spec.SpecSave(*opts.trigger, specFile) if err != nil { - return errors.Wrap(err, "error creating message queue trigger spec") + return errors.Wrap(err, "error saving message queue trigger spec") } return nil } diff --git a/pkg/fission-cli/cmd/package/command.go b/pkg/fission-cli/cmd/package/command.go index 330df60c..d5c8978b 100644 --- a/pkg/fission-cli/cmd/package/command.go +++ b/pkg/fission-cli/cmd/package/command.go @@ -33,7 +33,7 @@ func Commands() *cobra.Command { Required: []flag.Flag{flag.PkgEnvironment}, Optional: []flag.Flag{flag.PkgName, flag.PkgCode, flag.PkgSrcArchive, flag.PkgDeployArchive, flag.PkgSrcChecksum, flag.PkgDeployChecksum, flag.PkgInsecure, flag.PkgBuildCmd, - flag.NamespacePackage, flag.NamespaceEnvironment, flag.SpecSave}, + flag.NamespacePackage, flag.NamespaceEnvironment, flag.SpecSave, flag.SpecDry}, }) getSrcCmd := &cobra.Command{ diff --git a/pkg/fission-cli/cmd/package/create.go b/pkg/fission-cli/cmd/package/create.go index 45bc5e30..34d1ee14 100644 --- a/pkg/fission-cli/cmd/package/create.go +++ b/pkg/fission-cli/cmd/package/create.go @@ -134,7 +134,7 @@ func CreatePackage(input cli.Input, client client.Interface, pkgName string, pkg if len(specFile) > 0 { // we should do this in all cases, i think pkgStatus = fv1.BuildStatusNone } - deployment, err := CreateArchive(client, deployArchiveFiles, noZip, insecure, deployChecksum, specDir, specFile) + deployment, err := CreateArchive(client, input, deployArchiveFiles, noZip, insecure, deployChecksum, specDir, specFile) if err != nil { return nil, errors.Wrap(err, "error creating source archive") } @@ -144,7 +144,7 @@ func CreatePackage(input cli.Input, client client.Interface, pkgName string, pkg } } if len(srcArchiveFiles) > 0 { - source, err := CreateArchive(client, srcArchiveFiles, false, insecure, srcChecksum, specDir, specFile) + source, err := CreateArchive(client, input, srcArchiveFiles, false, insecure, srcChecksum, specDir, specFile) if err != nil { return nil, errors.Wrap(err, "error creating deploy archive") } @@ -175,7 +175,11 @@ func CreatePackage(input cli.Input, client client.Interface, pkgName string, pkg }, } - if len(specFile) > 0 { + if input.Bool(flagkey.SpecDry) { + return &pkg.ObjectMeta, spec.SpecDry(*pkg) + } + + if input.Bool(flagkey.SpecSave) { // if a package with the same spec exists, don't create a new spec file fr, err := spec.ReadSpecs(util.GetSpecDir(input)) if err != nil { diff --git a/pkg/fission-cli/cmd/package/package.go b/pkg/fission-cli/cmd/package/package.go index 4022f21c..3891fc64 100644 --- a/pkg/fission-cli/cmd/package/package.go +++ b/pkg/fission-cli/cmd/package/package.go @@ -31,6 +31,7 @@ import ( fv1 "github.com/fission/fission/pkg/apis/core/v1" "github.com/fission/fission/pkg/controller/client" + "github.com/fission/fission/pkg/fission-cli/cliwrapper/cli" pkgutil "github.com/fission/fission/pkg/fission-cli/cmd/package/util" "github.com/fission/fission/pkg/fission-cli/cmd/spec" spectypes "github.com/fission/fission/pkg/fission-cli/cmd/spec/types" @@ -45,7 +46,7 @@ import ( // create an archive upload spec in the specs directory; otherwise // upload the archive using client. noZip avoids zipping the // includeFiles, but is ignored if there's more than one includeFile. -func CreateArchive(client client.Interface, includeFiles []string, noZip bool, insecure bool, checksum string, specDir string, specFile string) (*fv1.Archive, error) { +func CreateArchive(client client.Interface, input cli.Input, includeFiles []string, noZip bool, insecure bool, checksum string, specDir string, specFile string) (*fv1.Archive, error) { // get root dir var rootDir string var err error @@ -56,7 +57,6 @@ func CreateArchive(client client.Interface, includeFiles []string, noZip bool, i return nil, errors.Wrapf(err, "error getting root directory of spec directory") } } - errs := utils.MultiErrorWithFormat() fileURL := "" @@ -143,31 +143,39 @@ func CreateArchive(client client.Interface, includeFiles []string, noZip bool, i }, nil } - if len(specFile) > 0 { + if input.Bool(flagkey.SpecSave) || input.Bool(flagkey.SpecDry) { // create an ArchiveUploadSpec and reference it from the archive aus := &spectypes.ArchiveUploadSpec{ Name: archiveName("", includeFiles), IncludeGlobs: includeFiles, } - // check if this AUS exists in the specs; if so, don't create a new one - fr, err := spec.ReadSpecs(specDir) - if err != nil { - return nil, errors.Wrap(err, "error reading specs") - } - - obj := fr.SpecExists(aus, true, true) - if obj != nil { - oldAus := obj.(*spectypes.ArchiveUploadSpec) - fmt.Printf("Re-using previously created archive %v\n", oldAus.Name) - aus.Name = oldAus.Name - } else { - // save the uploadspec - err := spec.SpecSave(*aus, specFile) + if input.Bool(flagkey.SpecDry) { + err := spec.SpecDry(*aus) if err != nil { - return nil, errors.Wrapf(err, "write spec file %v", specFile) + return nil, err + } + } else if input.Bool(flagkey.SpecSave) { + // check if this AUS exists in the specs; if so, don't create a new one + fr, err := spec.ReadSpecs(specDir) + if err != nil { + return nil, errors.Wrap(err, "error reading specs") + } + + obj := fr.SpecExists(aus, true, true) + if obj != nil { + oldAus := obj.(*spectypes.ArchiveUploadSpec) + fmt.Printf("Re-using previously created archive %v\n", oldAus.Name) + aus.Name = oldAus.Name + } else { + // save the uploadspec + err := spec.SpecSave(*aus, specFile) + if err != nil { + return nil, errors.Wrap(err, "error saving archive spec") + } } } + // create the archive object archive := fv1.Archive{ Type: fv1.ArchiveTypeUrl, diff --git a/pkg/fission-cli/cmd/package/update.go b/pkg/fission-cli/cmd/package/update.go index 1f3ceae7..647fec75 100644 --- a/pkg/fission-cli/cmd/package/update.go +++ b/pkg/fission-cli/cmd/package/update.go @@ -132,7 +132,7 @@ func UpdatePackage(input cli.Input, client client.Interface, pkg *fv1.Package) ( } if input.IsSet(flagkey.PkgSrcArchive) { - srcArchive, err := CreateArchive(client, srcArchiveFiles, noZip, insecure, srcChecksum, "", "") + srcArchive, err := CreateArchive(client, input, srcArchiveFiles, noZip, insecure, srcChecksum, "", "") if err != nil { return nil, errors.Wrap(err, "error creating source archive") } @@ -148,7 +148,7 @@ func UpdatePackage(input cli.Input, client client.Interface, pkg *fv1.Package) ( } if input.IsSet(flagkey.PkgDeployArchive) || input.IsSet(flagkey.PkgCode) { - deployArchive, err := CreateArchive(client, deployArchiveFiles, noZip, insecure, deployChecksum, "", "") + deployArchive, err := CreateArchive(client, input, deployArchiveFiles, noZip, insecure, deployChecksum, "", "") if err != nil { return nil, errors.Wrap(err, "error creating deploy archive") } diff --git a/pkg/fission-cli/cmd/spec/spec.go b/pkg/fission-cli/cmd/spec/spec.go index 936cb37a..bcdec8e3 100644 --- a/pkg/fission-cli/cmd/spec/spec.go +++ b/pkg/fission-cli/cmd/spec/spec.go @@ -164,13 +164,54 @@ func save(data []byte, specDir string, specFile string) error { // called from `fission * create --spec` func SpecSave(resource interface{}, specFile string) error { - var meta metav1.ObjectMeta - var kind string var specDir = "specs" + meta, kind, data, err := crdToYaml(resource) + if err != nil { + return err + } + + fr, err := ReadSpecs(specDir) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("error reading spec in '%v'", specDir)) + } + + exists, err := fr.ExistsInSpecs(resource) + if err != nil { + return err + } + + if exists { + return errors.Errorf("same name resource (%v) already exists in namespace (%v)", meta.Name, meta.Namespace) + } + + err = save(data, specDir, specFile) + if err != nil { + return err + } + + console.Info(fmt.Sprintf("Saving %v '%v/%v' to '%v/%v'", + kind, meta.Namespace, meta.Name, specDir, specFile)) + + return nil +} + +func SpecDry(resource interface{}) error { + _, _, data, err := crdToYaml(resource) + if err != nil { + return err + } + fmt.Println(string(data)) + return nil +} + +func crdToYaml(resource interface{}) (metav1.ObjectMeta, string, []byte, error) { // make sure we're writing a known type + var meta metav1.ObjectMeta + var kind string var data []byte var err error + switch typedres := resource.(type) { case types.ArchiveUploadSpec: typedres.Kind = "ArchiveUploadSpec" @@ -222,35 +263,14 @@ func SpecSave(resource interface{}, specFile string) error { kind = typedres.TypeMeta.Kind data, err = yaml.Marshal(typedres) default: - return fmt.Errorf("can't save resource %#v", resource) + err = errors.Errorf("unknown object type '%v'", typedres) } + if err != nil { - return errors.Wrap(err, "Couldn't marshal YAML") + return metav1.ObjectMeta{}, "", nil, errors.Wrap(err, "couldn't marshal YAML") } - fr, err := ReadSpecs(specDir) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("error reading spec in '%v'", specDir)) - } - - exists, err := fr.ExistsInSpecs(resource) - if err != nil { - return err - } - - if exists { - return errors.Errorf("same name resource (%v) already exists in namespace (%v)", meta.Name, meta.Namespace) - } - - err = save(data, specDir, specFile) - if err != nil { - return err - } - - console.Info(fmt.Sprintf("Saving %v '%v/%v' to '%v/%v'", - kind, meta.Namespace, meta.Name, specDir, specFile)) - - return nil + return meta, kind, data, nil } // validateFunctionReference checks a function reference diff --git a/pkg/fission-cli/cmd/timetrigger/command.go b/pkg/fission-cli/cmd/timetrigger/command.go index e86c1f9d..4614f3c1 100644 --- a/pkg/fission-cli/cmd/timetrigger/command.go +++ b/pkg/fission-cli/cmd/timetrigger/command.go @@ -31,7 +31,7 @@ func Commands() *cobra.Command { } wrapper.SetFlags(createCmd, flag.FlagSet{ Optional: []flag.Flag{flag.TtName, flag.TtFnName, - flag.TtCron, flag.NamespaceFunction, flag.SpecSave}, + flag.TtCron, flag.NamespaceFunction, flag.SpecSave, flag.SpecDry}, }) updateCmd := &cobra.Command{ diff --git a/pkg/fission-cli/cmd/timetrigger/create.go b/pkg/fission-cli/cmd/timetrigger/create.go index 5883aefe..fca3a863 100644 --- a/pkg/fission-cli/cmd/timetrigger/create.go +++ b/pkg/fission-cli/cmd/timetrigger/create.go @@ -111,11 +111,16 @@ func (opts *CreateSubCommand) complete(input cli.Input) error { func (opts *CreateSubCommand) run(input cli.Input) error { // if we're writing a spec, don't call the API + // save to spec file or display the spec to console + if input.Bool(flagkey.SpecDry) { + return spec.SpecDry(*opts.trigger) + } + if input.Bool(flagkey.SpecSave) { specFile := fmt.Sprintf("timetrigger-%v.yaml", opts.trigger.ObjectMeta.Name) err := spec.SpecSave(*opts.trigger, specFile) if err != nil { - return errors.Wrap(err, "error creating time trigger spec") + return errors.Wrap(err, "error saving time trigger spec") } return nil } diff --git a/pkg/fission-cli/flag/flag.go b/pkg/fission-cli/flag/flag.go index 690536b6..84177c67 100644 --- a/pkg/fission-cli/flag/flag.go +++ b/pkg/fission-cli/flag/flag.go @@ -170,6 +170,7 @@ var ( SpecWait = Flag{Type: Bool, Name: flagkey.SpecWait, Usage: "Wait for package builds"} SpecWatch = Flag{Type: Bool, Name: flagkey.SpecWatch, Usage: "Watch local files for change, and re-apply specs as necessary"} SpecDelete = Flag{Type: Bool, Name: flagkey.SpecDelete, Usage: "Allow apply to delete resources that no longer exist in the specification"} + SpecDry = Flag{Type: Bool, Name: flagkey.SpecDry, Usage: "View the generated specs"} SupportOutput = Flag{Type: String, Name: flagkey.SupportOutput, Short: "o", Usage: "Output directory to save dump archive/files", DefaultValue: flagkey.DefaultSpecOutputDir} SupportNoZip = Flag{Type: Bool, Name: flagkey.SupportNoZip, Usage: "Save dump information into multiple files instead of single zip file"} diff --git a/pkg/fission-cli/flag/key/key.go b/pkg/fission-cli/flag/key/key.go index 2c29aff0..5aee2032 100644 --- a/pkg/fission-cli/flag/key/key.go +++ b/pkg/fission-cli/flag/key/key.go @@ -125,6 +125,7 @@ const ( SpecWait = "wait" SpecWatch = "watch" SpecDelete = "delete" + SpecDry = "dry" SupportOutput = Output SupportNoZip = "nozip"