From 68dbff6550f3182eac009049df8d8c3e17dfe27e Mon Sep 17 00:00:00 2001 From: Denis Makogon Date: Fri, 7 Sep 2018 23:44:35 -0400 Subject: [PATCH 1/4] DeployAll: make DeployAll method reusable out of the CLI - Why? DeployAll is the exact method that encapsulates a lot of useful logic and can be reused to run the deploy against a folder within other tools. --- commands/deploy.go | 80 +++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/commands/deploy.go b/commands/deploy.go index a9f9d308..54c4dfa2 100644 --- a/commands/deploy.go +++ b/commands/deploy.go @@ -223,24 +223,21 @@ func (p *deploycmd) deploySingle(c *cli.Context, appName string, appf *common.Ap } } -// deployAll deploys all functions in an app. -func (p *deploycmd) deployAll(c *cli.Context, appName string, appf *common.AppFile) error { +func DeployAll(client *fnclient.Fn, buildArgs []string, verbose bool, noBump, isLocal, noCache bool, appDir, appName string, appf *common.AppFile) error { if appf != nil { - err := p.updateAppConfig(appf) + err := UpdateAppConfig(client, appf) if err != nil { - return fmt.Errorf("Failed to update app config: %v", err) + return fmt.Errorf("failed to update app config: %v", err) } } - var dir string wd := common.GetWd() - if c.String("dir") != "" { - dir = c.String("dir") + if appDir != "" { + dir = appDir } else { dir = wd } - var funcFound bool err := common.WalkFuncs(dir, func(path string, ff *common.FuncFile, err error) error { if err != nil { // probably some issue with funcfile parsing, can decide to handle this differently if we'd like @@ -268,7 +265,7 @@ func (p *deploycmd) deployAll(c *cli.Context, appName string, appf *common.AppFi } } - err = p.deployFunc(c, appName, wd, path, ff) + err = DeployFunc(client, buildArgs, verbose, noBump, isLocal, noCache, appName, path, ff) if err != nil { return fmt.Errorf("deploy error on %s: %v", path, err) } @@ -282,21 +279,23 @@ func (p *deploycmd) deployAll(c *cli.Context, appName string, appf *common.AppFi return err } - if !funcFound { - return errors.New("No functions found to deploy") - } - return nil } -// deployFunc performs several actions to deploy to a functions server. -// Parse func.yaml file, bump version, build image, push to registry, and -// finally it will update function's route. Optionally, -// the route can be overriden inside the func.yaml file. -func (p *deploycmd) deployFunc(c *cli.Context, appName, baseDir, funcfilePath string, funcfile *common.FuncFile) error { +// deployAll deploys all functions in an app. +func (p *deploycmd) deployAll(c *cli.Context, appName string, appf *common.AppFile) error { if appName == "" { return errors.New("App name must be provided, try `--app APP_NAME`") } + + return DeployAll( + p.client, c.StringSlice("build-args"), + c.GlobalBool("verbose"), p.noBump, + p.local, p.noCache, + c.String("dir"), appName, appf) +} + +func DeployFunc(client *fnclient.Fn, buildArgs []string, verbose bool, noBump, isLocal, noCache bool, appName, funcfilePath string, funcfile *common.FuncFile) error { dir := filepath.Dir(funcfilePath) // get name from directory if it's not defined if funcfile.Name == "" { @@ -313,7 +312,8 @@ func (p *deploycmd) deployFunc(c *cli.Context, appName, baseDir, funcfilePath st fmt.Printf("Deploying %s to app: %s at path: %s\n", funcfile.Name, appName, funcfile.Path) var err error - if !p.noBump { + //p.noBump + if !noBump { funcfile2, err := common.BumpIt(funcfilePath, common.Patch) if err != nil { return err @@ -322,19 +322,32 @@ func (p *deploycmd) deployFunc(c *cli.Context, appName, baseDir, funcfilePath st // TODO: this whole funcfile handling needs some love, way too confusing. Only bump makes permanent changes to it. } - buildArgs := c.StringSlice("build-arg") - _, err = common.BuildFunc(c.GlobalBool("verbose"), funcfilePath, funcfile, buildArgs, p.noCache) + // p.noCache + _, err = common.BuildFunc(verbose, funcfilePath, funcfile, buildArgs, noCache) if err != nil { return err } - if !p.local { + // p.local + if !isLocal { if err := common.DockerPush(funcfile); err != nil { return err } } - return p.updateRoute(c, appName, funcfile) + return UpdateRoute(client, appName, funcfile) +} + +// deployFunc performs several actions to deploy to a functions server. +// Parse func.yaml file, bump version, build image, push to registry, and +// finally it will update function's route. Optionally, +// the route can be overriden inside the func.yaml file. +func (p *deploycmd) deployFunc(c *cli.Context, appName, baseDir, funcfilePath string, funcfile *common.FuncFile) error { + if appName == "" { + return errors.New("App name must be provided, try `--app APP_NAME`") + } + return DeployFunc(p.client, c.StringSlice("build-args"), c.GlobalBool("verbose"), + p.noBump, p.local, p.noCache, appName, funcfilePath, funcfile) } func (p *deploycmd) deployFuncV20180708(c *cli.Context, appName, baseDir, funcfilePath string, funcfile *common.FuncFileV20180708) error { @@ -390,13 +403,18 @@ func setFuncInfoV20180708(ff *common.FuncFileV20180708, appName string) { } } -func (p *deploycmd) updateRoute(c *cli.Context, appName string, ff *common.FuncFile) error { - fmt.Printf("Updating route %s using image %s...\n", ff.Path, ff.ImageName()) +func UpdateRoute(client *fnclient.Fn, appName string, ff *common.FuncFile) error { rt := &models.Route{} if err := route.WithFuncFile(ff, rt); err != nil { return fmt.Errorf("Error getting route with funcfile: %s", err) } - return route.PutRoute(p.client, appName, ff.Path, rt) + return route.PutRoute(client, appName, ff.Path, rt) + +} + +func (p *deploycmd) updateRoute(appName string, ff *common.FuncFile) error { + fmt.Printf("Updating route %s using image %s...\n", ff.Path, ff.ImageName()) + return UpdateRoute(p.client, appName, ff) } func (p *deploycmd) updateFunction(c *cli.Context, appName string, ff *common.FuncFileV20180708) error { @@ -479,7 +497,7 @@ func expandEnvConfig(configs map[string]string) map[string]string { return configs } -func (p *deploycmd) updateAppConfig(appf *common.AppFile) error { +func UpdateAppConfig(client *fnclient.Fn, appf *common.AppFile) error { param := clientApps.NewPatchAppsAppParams() param.App = appf.Name param.Body = &models.AppWrapper{ @@ -489,7 +507,7 @@ func (p *deploycmd) updateAppConfig(appf *common.AppFile) error { }, } - _, err := p.client.Apps.PatchAppsApp(param) + _, err := client.Apps.PatchAppsApp(param) if err != nil { postParams := clientApps.NewPostAppsParams() //XXX switch to put when v2.0 Fn postParams.Body = &models.AppWrapper{ @@ -500,10 +518,14 @@ func (p *deploycmd) updateAppConfig(appf *common.AppFile) error { }, } - _, err = p.client.Apps.PostApps(postParams) + _, err = client.Apps.PostApps(postParams) if err != nil { return err } } return nil } + +func (p *deploycmd) updateAppConfig(appf *common.AppFile) error { + return UpdateAppConfig(p.client, appf) +} From 548b511916143ad19ebab88feaa028512a5d36d3 Mon Sep 17 00:00:00 2001 From: Denis Makogon Date: Sun, 9 Sep 2018 20:49:18 +0300 Subject: [PATCH 2/4] DeploySingle: internal signature change - extracting DeploySingle core API method --- commands/deploy.go | 356 ++++---------------------------------- commands/deploy_api.go | 203 ++++++++++++++++++++++ commands/functions_api.go | 96 ++++++++++ 3 files changed, 328 insertions(+), 327 deletions(-) create mode 100644 commands/deploy_api.go create mode 100644 commands/functions_api.go diff --git a/commands/deploy.go b/commands/deploy.go index 54c4dfa2..7afc255e 100644 --- a/commands/deploy.go +++ b/commands/deploy.go @@ -3,22 +3,14 @@ package commands import ( "errors" "fmt" - "os" "path/filepath" - "strings" - "time" - client "github.com/fnproject/cli/client" - common "github.com/fnproject/cli/common" - apps "github.com/fnproject/cli/objects/app" - function "github.com/fnproject/cli/objects/fn" - route "github.com/fnproject/cli/objects/route" - trigger "github.com/fnproject/cli/objects/trigger" + "github.com/fnproject/cli/client" + "github.com/fnproject/cli/common" fnclient "github.com/fnproject/fn_go/client" clientApps "github.com/fnproject/fn_go/client/apps" v2Client "github.com/fnproject/fn_go/clientv2" - models "github.com/fnproject/fn_go/models" - modelsV2 "github.com/fnproject/fn_go/modelsv2" + "github.com/fnproject/fn_go/models" "github.com/urfave/cli" ) @@ -147,8 +139,19 @@ func (p *deploycmd) deploy(c *cli.Context) error { return errors.New("App name must be provided, try `--app APP_NAME`") } + buildArgs := c.StringSlice("build-arg") + verbose := c.GlobalBool("verbose") + noBump := p.noBump + isLocal := p.local + noCache := p.noCache + appDir := c.String("dir") + if p.all { - return p.deployAll(c, appName, appf) + return DeployAll( + p.client, buildArgs, + verbose, noBump, + isLocal, noCache, + appDir, appName, appf) } return p.deploySingle(c, appName, appf) } @@ -159,230 +162,27 @@ func (p *deploycmd) deploySingle(c *cli.Context, appName string, appf *common.Ap var dir string wd := common.GetWd() - if c.String("working-dir") != "" { - dir = c.String("working-dir") - } else { - // if we're in the context of an app, first arg is path to the function - path := c.Args().First() - if path != "" { - fmt.Printf("Deploying function at: /%s\n", path) - } - dir = filepath.Join(wd, path) - } - - err := os.Chdir(dir) - if err != nil { - return err - } - defer os.Chdir(wd) - - ffV, err := common.ReadInFuncFile() - if err != nil { - return err - } - - switch common.GetFuncYamlVersion(ffV) { - case common.LatestYamlVersion: - fpath, ff, err := common.FindAndParseFuncFileV20180708(dir) - if err != nil { - return err - } - if appf != nil { - if dir == wd { - setFuncInfoV20180708(ff, appf.Name) - } - } - - if appf != nil { - err = p.updateAppConfig(appf) - if err != nil { - return fmt.Errorf("Failed to update app config: %v", err) - } - } - - return p.deployFuncV20180708(c, appName, wd, fpath, ff) - default: - fpath, ff, err := common.FindAndParseFuncfile(dir) - if err != nil { - return err - } - if appf != nil { - if dir == wd { - setRootFuncInfo(ff, appf.Name) - } - } - - if appf != nil { - err = p.updateAppConfig(appf) - if err != nil { - return fmt.Errorf("Failed to update app config: %v", err) - } - } - - return p.deployFunc(c, appName, wd, fpath, ff) - } -} - -func DeployAll(client *fnclient.Fn, buildArgs []string, verbose bool, noBump, isLocal, noCache bool, appDir, appName string, appf *common.AppFile) error { - if appf != nil { - err := UpdateAppConfig(client, appf) - if err != nil { - return fmt.Errorf("failed to update app config: %v", err) - } - } - var dir string - wd := common.GetWd() + fpath := c.Args().First() + workingDir := c.String("working-dir") - if appDir != "" { - dir = appDir + if workingDir != "" { + dir = workingDir } else { - dir = wd - } - var funcFound bool - err := common.WalkFuncs(dir, func(path string, ff *common.FuncFile, err error) error { - if err != nil { // probably some issue with funcfile parsing, can decide to handle this differently if we'd like - return err - } - dir := filepath.Dir(path) - if dir == wd { - setRootFuncInfo(ff, appName) - } else { - // change dirs - err = os.Chdir(dir) - if err != nil { - return err - } - p2 := strings.TrimPrefix(dir, wd) - if ff.Name == "" { - ff.Name = strings.Replace(p2, "/", "-", -1) - if strings.HasPrefix(ff.Name, "-") { - ff.Name = ff.Name[1:] - } - // todo: should we prefix appname too? - } - if ff.Path == "" { - ff.Path = p2 - } - } - - err = DeployFunc(client, buildArgs, verbose, noBump, isLocal, noCache, appName, path, ff) - if err != nil { - return fmt.Errorf("deploy error on %s: %v", path, err) - } - - now := time.Now() - os.Chtimes(path, now, now) - funcFound = true - return nil - }) - if err != nil { - return err - } - - return nil -} - -// deployAll deploys all functions in an app. -func (p *deploycmd) deployAll(c *cli.Context, appName string, appf *common.AppFile) error { - if appName == "" { - return errors.New("App name must be provided, try `--app APP_NAME`") - } - - return DeployAll( - p.client, c.StringSlice("build-args"), - c.GlobalBool("verbose"), p.noBump, - p.local, p.noCache, - c.String("dir"), appName, appf) -} - -func DeployFunc(client *fnclient.Fn, buildArgs []string, verbose bool, noBump, isLocal, noCache bool, appName, funcfilePath string, funcfile *common.FuncFile) error { - dir := filepath.Dir(funcfilePath) - // get name from directory if it's not defined - if funcfile.Name == "" { - funcfile.Name = filepath.Base(filepath.Dir(funcfilePath)) // todo: should probably make a copy of ff before changing it - } - if funcfile.Path == "" { - if dir == "." { - funcfile.Path = "/" - } else { - funcfile.Path = "/" + filepath.Base(dir) - } - - } - fmt.Printf("Deploying %s to app: %s at path: %s\n", funcfile.Name, appName, funcfile.Path) - - var err error - //p.noBump - if !noBump { - funcfile2, err := common.BumpIt(funcfilePath, common.Patch) - if err != nil { - return err - } - funcfile.Version = funcfile2.Version - // TODO: this whole funcfile handling needs some love, way too confusing. Only bump makes permanent changes to it. - } - - // p.noCache - _, err = common.BuildFunc(verbose, funcfilePath, funcfile, buildArgs, noCache) - if err != nil { - return err - } - - // p.local - if !isLocal { - if err := common.DockerPush(funcfile); err != nil { - return err - } - } - - return UpdateRoute(client, appName, funcfile) -} - -// deployFunc performs several actions to deploy to a functions server. -// Parse func.yaml file, bump version, build image, push to registry, and -// finally it will update function's route. Optionally, -// the route can be overriden inside the func.yaml file. -func (p *deploycmd) deployFunc(c *cli.Context, appName, baseDir, funcfilePath string, funcfile *common.FuncFile) error { - if appName == "" { - return errors.New("App name must be provided, try `--app APP_NAME`") - } - return DeployFunc(p.client, c.StringSlice("build-args"), c.GlobalBool("verbose"), - p.noBump, p.local, p.noCache, appName, funcfilePath, funcfile) -} - -func (p *deploycmd) deployFuncV20180708(c *cli.Context, appName, baseDir, funcfilePath string, funcfile *common.FuncFileV20180708) error { - if appName == "" { - return errors.New("App name must be provided, try `--app APP_NAME`") - } - - if funcfile.Name == "" { - funcfile.Name = filepath.Base(filepath.Dir(funcfilePath)) // todo: should probably make a copy of ff before changing it - } - fmt.Printf("Deploying %s to app: %s\n", funcfile.Name, appName) - - var err error - if !p.noBump { - funcfile2, err := common.BumpItV20180708(funcfilePath, common.Patch) - if err != nil { - return err + // if we're in the context of an app, first arg is path to the function + if fpath != "" { + fmt.Printf("Deploying function at: /%s\n", fpath) } - funcfile.Version = funcfile2.Version - // TODO: this whole funcfile handling needs some love, way too confusing. Only bump makes permanent changes to it. + dir = filepath.Join(wd, fpath) } buildArgs := c.StringSlice("build-arg") - _, err = common.BuildFuncV20180708(c.GlobalBool("verbose"), funcfilePath, funcfile, buildArgs, p.noCache) - if err != nil { - return err - } + verbose := c.GlobalBool("verbose") + noBump := p.noBump + isLocal := p.local + noCache := p.noCache - if !p.local { - if err := common.DockerPushV20180708(funcfile); err != nil { - return err - } - } - - return p.updateFunction(c, appName, funcfile) + return DeploySingle(p.client, p.clientV2, buildArgs, verbose, + noBump, isLocal, noCache, dir, appName, appf) } func setRootFuncInfo(ff *common.FuncFile, appName string) { @@ -403,100 +203,6 @@ func setFuncInfoV20180708(ff *common.FuncFileV20180708, appName string) { } } -func UpdateRoute(client *fnclient.Fn, appName string, ff *common.FuncFile) error { - rt := &models.Route{} - if err := route.WithFuncFile(ff, rt); err != nil { - return fmt.Errorf("Error getting route with funcfile: %s", err) - } - return route.PutRoute(client, appName, ff.Path, rt) - -} - -func (p *deploycmd) updateRoute(appName string, ff *common.FuncFile) error { - fmt.Printf("Updating route %s using image %s...\n", ff.Path, ff.ImageName()) - return UpdateRoute(p.client, appName, ff) -} - -func (p *deploycmd) updateFunction(c *cli.Context, appName string, ff *common.FuncFileV20180708) error { - fmt.Printf("Updating function %s using image %s...\n", ff.Name, ff.ImageNameV20180708()) - fn := &modelsV2.Fn{} - if err := function.WithFuncFileV20180708(ff, fn); err != nil { - return fmt.Errorf("Error getting route with funcfile: %s", err) - } - - app, err := apps.GetAppByName(appName) - if err != nil { - app = &models.App{ - Name: appName, - } - - err = apps.CreateApp(p.client, app) - if err != nil { - return err - } - app, err = apps.GetAppByName(appName) - if err != nil { - return err - } - } - - fnRes, err := function.GetFnByName(p.clientV2, app.ID, ff.Name) - if err != nil { - fn.Name = ff.Name - err := function.CreateFn(p.clientV2, appName, fn) - if err != nil { - return err - } - } else { - fn.ID = fnRes.ID - err = function.PutFn(p.clientV2, fn.ID, fn) - if err != nil { - return err - } - } - - if fnRes == nil { - fn, err = function.GetFnByName(p.clientV2, app.ID, ff.Name) - if err != nil { - return err - } - } - - if len(ff.Triggers) != 0 { - for _, t := range ff.Triggers { - trig := &modelsV2.Trigger{ - AppID: app.ID, - FnID: fn.ID, - Name: t.Name, - Source: t.Source, - Type: t.Type, - } - - trigs, err := trigger.GetTriggerByName(p.clientV2, app.ID, fn.ID, t.Name) - if err != nil { - err = trigger.CreateTrigger(p.clientV2, trig) - if err != nil { - return err - } - } else { - trig.ID = trigs.ID - err = trigger.PutTrigger(p.clientV2, trig) - if err != nil { - return err - } - } - } - } - - return nil -} -func expandEnvConfig(configs map[string]string) map[string]string { - for k, v := range configs { - configs[k] = os.ExpandEnv(v) - } - return configs -} - func UpdateAppConfig(client *fnclient.Fn, appf *common.AppFile) error { param := clientApps.NewPatchAppsAppParams() param.App = appf.Name @@ -525,7 +231,3 @@ func UpdateAppConfig(client *fnclient.Fn, appf *common.AppFile) error { } return nil } - -func (p *deploycmd) updateAppConfig(appf *common.AppFile) error { - return UpdateAppConfig(p.client, appf) -} diff --git a/commands/deploy_api.go b/commands/deploy_api.go new file mode 100644 index 00000000..6164e2f4 --- /dev/null +++ b/commands/deploy_api.go @@ -0,0 +1,203 @@ +package commands + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "time" + + "github.com/fnproject/cli/common" + fnclient "github.com/fnproject/fn_go/client" + v2Client "github.com/fnproject/fn_go/clientv2" +) + +func DeploySingle(clientV1 *fnclient.Fn, clientV2 *v2Client.Fn, buildArgs []string, verbose bool, noBump, isLocal, noCache bool, dir, appName string, appf *common.AppFile) error { + wd := common.GetWd() + + err := os.Chdir(dir) + if err != nil { + return err + } + defer os.Chdir(dir) + + ffV, err := common.ReadInFuncFile() + if err != nil { + return err + } + + switch common.GetFuncYamlVersion(ffV) { + case common.LatestYamlVersion: + fpath, ff, err := common.FindAndParseFuncFileV20180708(dir) + if err != nil { + return err + } + if appf != nil { + if dir == wd { + setFuncInfoV20180708(ff, appf.Name) + } + } + + if appf != nil { + err = UpdateAppConfig(clientV1, appf) + if err != nil { + return fmt.Errorf("Failed to update app config: %v", err) + } + } + + return DeployFuncV20180708(clientV1, clientV2, buildArgs, verbose, noBump, + isLocal, noCache, appName, fpath, ff) + default: + fpath, ff, err := common.FindAndParseFuncfile(dir) + if err != nil { + return err + } + if appf != nil { + if dir == wd { + setRootFuncInfo(ff, appf.Name) + } + } + + if appf != nil { + err = UpdateAppConfig(clientV1, appf) + if err != nil { + return fmt.Errorf("Failed to update app config: %v", err) + } + } + + return DeployFunc(clientV1, buildArgs, verbose, noBump, isLocal, noCache, appName, fpath, ff) + } +} + +func DeployAll(client *fnclient.Fn, buildArgs []string, verbose bool, noBump, isLocal, noCache bool, appDir, appName string, appf *common.AppFile) error { + if appf != nil { + err := UpdateAppConfig(client, appf) + if err != nil { + return fmt.Errorf("failed to update app config: %v", err) + } + } + var dir string + wd := common.GetWd() + + if appDir != "" { + dir = appDir + } else { + dir = wd + } + var funcFound bool + err := common.WalkFuncs(dir, func(path string, ff *common.FuncFile, err error) error { + if err != nil { // probably some issue with funcfile parsing, can decide to handle this differently if we'd like + return err + } + dir := filepath.Dir(path) + if dir == wd { + setRootFuncInfo(ff, appName) + } else { + // change dirs + err = os.Chdir(dir) + if err != nil { + return err + } + p2 := strings.TrimPrefix(dir, wd) + if ff.Name == "" { + ff.Name = strings.Replace(p2, "/", "-", -1) + if strings.HasPrefix(ff.Name, "-") { + ff.Name = ff.Name[1:] + } + // todo: should we prefix appname too? + } + if ff.Path == "" { + ff.Path = p2 + } + } + + err = DeployFunc(client, buildArgs, verbose, noBump, isLocal, noCache, appName, path, ff) + if err != nil { + return fmt.Errorf("deploy error on %s: %v", path, err) + } + + now := time.Now() + os.Chtimes(path, now, now) + funcFound = true + return nil + }) + if err != nil { + return err + } + + return nil +} + +// DeployFunc performs several actions to deploy to a functions server. +// Parse func.yaml file, bump version, build image, push to registry, and +// finally it will update function's route. Optionally, +// the route can be overriden inside the func.yaml file. +func DeployFunc(client *fnclient.Fn, buildArgs []string, verbose bool, noBump, isLocal, noCache bool, appName, funcfilePath string, funcfile *common.FuncFile) error { + dir := filepath.Dir(funcfilePath) + // get name from directory if it's not defined + if funcfile.Name == "" { + funcfile.Name = filepath.Base(filepath.Dir(funcfilePath)) // todo: should probably make a copy of ff before changing it + } + if funcfile.Path == "" { + if dir == "." { + funcfile.Path = "/" + } else { + funcfile.Path = "/" + filepath.Base(dir) + } + + } + + var err error + if !noBump { + funcfile2, err := common.BumpIt(funcfilePath, common.Patch) + if err != nil { + return err + } + funcfile.Version = funcfile2.Version + // TODO: this whole funcfile handling needs some love, way too confusing. Only bump makes permanent changes to it. + } + + // p.noCache + _, err = common.BuildFunc(verbose, funcfilePath, funcfile, buildArgs, noCache) + if err != nil { + return err + } + + // p.local + if !isLocal { + if err := common.DockerPush(funcfile); err != nil { + return err + } + } + + return updateRoute(client, appName, funcfile) +} + +func DeployFuncV20180708(clientV1 *fnclient.Fn, clientV2 *v2Client.Fn, buildArgs []string, verbose bool, noBump, isLocal, noCache bool, appName, funcfilePath string, funcfile *common.FuncFileV20180708) error { + if funcfile.Name == "" { + funcfile.Name = filepath.Base(filepath.Dir(funcfilePath)) // todo: should probably make a copy of ff before changing it + } + + var err error + if !noBump { + funcfile2, err := common.BumpItV20180708(funcfilePath, common.Patch) + if err != nil { + return err + } + funcfile.Version = funcfile2.Version + // TODO: this whole funcfile handling needs some love, way too confusing. Only bump makes permanent changes to it. + } + + _, err = common.BuildFuncV20180708(verbose, funcfilePath, funcfile, buildArgs, noCache) + if err != nil { + return err + } + + if !isLocal { + if err := common.DockerPushV20180708(funcfile); err != nil { + return err + } + } + + return updateFunction(clientV1, clientV2, appName, funcfile) +} diff --git a/commands/functions_api.go b/commands/functions_api.go new file mode 100644 index 00000000..a586347e --- /dev/null +++ b/commands/functions_api.go @@ -0,0 +1,96 @@ +package commands + +import ( + "fmt" + + "github.com/fnproject/cli/common" + apps "github.com/fnproject/cli/objects/app" + function "github.com/fnproject/cli/objects/fn" + "github.com/fnproject/cli/objects/route" + "github.com/fnproject/cli/objects/trigger" + fnclient "github.com/fnproject/fn_go/client" + v2Client "github.com/fnproject/fn_go/clientv2" + "github.com/fnproject/fn_go/models" + modelsV2 "github.com/fnproject/fn_go/modelsv2" +) + +func updateFunction(clientV1 *fnclient.Fn, clientV2 *v2Client.Fn, appName string, ff *common.FuncFileV20180708) error { + fn := &modelsV2.Fn{} + if err := function.WithFuncFileV20180708(ff, fn); err != nil { + return fmt.Errorf("Error getting route with funcfile: %s", err) + } + + app, err := apps.GetAppByName(appName) + if err != nil { + app = &models.App{ + Name: appName, + } + + err = apps.CreateApp(clientV1, app) + if err != nil { + return err + } + app, err = apps.GetAppByName(appName) + if err != nil { + return err + } + } + + fnRes, err := function.GetFnByName(clientV2, app.ID, ff.Name) + if err != nil { + fn.Name = ff.Name + err := function.CreateFn(clientV2, appName, fn) + if err != nil { + return err + } + } else { + fn.ID = fnRes.ID + err = function.PutFn(clientV2, fn.ID, fn) + if err != nil { + return err + } + } + + if fnRes == nil { + fn, err = function.GetFnByName(clientV2, app.ID, ff.Name) + if err != nil { + return err + } + } + + if len(ff.Triggers) != 0 { + for _, t := range ff.Triggers { + trig := &modelsV2.Trigger{ + AppID: app.ID, + FnID: fn.ID, + Name: t.Name, + Source: t.Source, + Type: t.Type, + } + + trigs, err := trigger.GetTriggerByName(clientV2, app.ID, fn.ID, t.Name) + if err != nil { + err = trigger.CreateTrigger(clientV2, trig) + if err != nil { + return err + } + } else { + trig.ID = trigs.ID + err = trigger.PutTrigger(clientV2, trig) + if err != nil { + return err + } + } + } + } + + return nil +} + +func updateRoute(client *fnclient.Fn, appName string, ff *common.FuncFile) error { + rt := &models.Route{} + if err := route.WithFuncFile(ff, rt); err != nil { + return fmt.Errorf("Error getting route with funcfile: %s", err) + } + return route.PutRoute(client, appName, ff.Path, rt) +} From 33cc0e24e36d0d9e1590ec091be50eb8bec2c2f0 Mon Sep 17 00:00:00 2001 From: Denis Makogon Date: Sun, 9 Sep 2018 21:06:25 +0300 Subject: [PATCH 3/4] DeployConfig: combine all CLI flags related to deploy into a DeployConfig DeployConfig represents a set of CLI args (deploy parameters) that are used for "fn deploy" DeployConfig makes method signatures shorter and simpler to read and work with --- commands/build.go | 6 ++++-- commands/deploy.go | 40 ++++++++++++++++++++-------------------- commands/deploy_api.go | 28 ++++++++++++++-------------- common/common.go | 4 ++-- run/run.go | 10 ++++++++-- 5 files changed, 48 insertions(+), 40 deletions(-) diff --git a/commands/build.go b/commands/build.go index e0a04d4c..7556da24 100644 --- a/commands/build.go +++ b/commands/build.go @@ -82,7 +82,7 @@ func (b *buildcmd) build(c *cli.Context) error { } buildArgs := c.StringSlice("build-arg") - ff, err = common.BuildFuncV20180708(c.GlobalBool("verbose"), fpath, ff, buildArgs, b.noCache) + ff, err = common.BuildFuncV20180708(buildArgs, c.GlobalBool("verbose"), b.noCache, fpath, ff) if err != nil { return err } @@ -97,7 +97,9 @@ func (b *buildcmd) build(c *cli.Context) error { } buildArgs := c.StringSlice("build-arg") - ff, err = common.BuildFunc(c.GlobalBool("verbose"), fpath, ff, buildArgs, b.noCache) + verbpse := c.GlobalBool("verbose") + + ff, err = common.BuildFunc(buildArgs, verbpse, b.noCache, fpath, ff) if err != nil { return err } diff --git a/commands/deploy.go b/commands/deploy.go index 7afc255e..fc1e66a0 100644 --- a/commands/deploy.go +++ b/commands/deploy.go @@ -139,26 +139,33 @@ func (p *deploycmd) deploy(c *cli.Context) error { return errors.New("App name must be provided, try `--app APP_NAME`") } - buildArgs := c.StringSlice("build-arg") - verbose := c.GlobalBool("verbose") - noBump := p.noBump - isLocal := p.local - noCache := p.noCache + deployConfig := &DeployConfig{ + c.StringSlice("build-arg"), + c.GlobalBool("verbose"), + p.noBump, + p.local, + p.noCache} + appDir := c.String("dir") if p.all { - return DeployAll( - p.client, buildArgs, - verbose, noBump, - isLocal, noCache, - appDir, appName, appf) + return DeployAll(p.client, deployConfig, appDir, appName, appf) } - return p.deploySingle(c, appName, appf) + + return p.deploySingle(c, deployConfig, appName, appf) +} + +type DeployConfig struct { + BuildArgs []string + Verbose bool + NoBump bool + IsLocal bool + NoCache bool } // deploySingle deploys a single function, either the current directory or if in the context // of an app and user provides relative path as the first arg, it will deploy that function. -func (p *deploycmd) deploySingle(c *cli.Context, appName string, appf *common.AppFile) error { +func (p *deploycmd) deploySingle(c *cli.Context, deployConfig *DeployConfig, appName string, appf *common.AppFile) error { var dir string wd := common.GetWd() @@ -175,14 +182,7 @@ func (p *deploycmd) deploySingle(c *cli.Context, appName string, appf *common.Ap dir = filepath.Join(wd, fpath) } - buildArgs := c.StringSlice("build-arg") - verbose := c.GlobalBool("verbose") - noBump := p.noBump - isLocal := p.local - noCache := p.noCache - - return DeploySingle(p.client, p.clientV2, buildArgs, verbose, - noBump, isLocal, noCache, dir, appName, appf) + return DeploySingle(p.client, p.clientV2, deployConfig, dir, appName, appf) } func setRootFuncInfo(ff *common.FuncFile, appName string) { diff --git a/commands/deploy_api.go b/commands/deploy_api.go index 6164e2f4..3f55e08a 100644 --- a/commands/deploy_api.go +++ b/commands/deploy_api.go @@ -12,7 +12,7 @@ import ( v2Client "github.com/fnproject/fn_go/clientv2" ) -func DeploySingle(clientV1 *fnclient.Fn, clientV2 *v2Client.Fn, buildArgs []string, verbose bool, noBump, isLocal, noCache bool, dir, appName string, appf *common.AppFile) error { +func DeploySingle(clientV1 *fnclient.Fn, clientV2 *v2Client.Fn, deployConfig *DeployConfig, dir, appName string, appf *common.AppFile) error { wd := common.GetWd() err := os.Chdir(dir) @@ -45,8 +45,7 @@ func DeploySingle(clientV1 *fnclient.Fn, clientV2 *v2Client.Fn, buildArgs []stri } } - return DeployFuncV20180708(clientV1, clientV2, buildArgs, verbose, noBump, - isLocal, noCache, appName, fpath, ff) + return DeployFuncV20180708(clientV1, clientV2, deployConfig, appName, fpath, ff) default: fpath, ff, err := common.FindAndParseFuncfile(dir) if err != nil { @@ -65,11 +64,11 @@ func DeploySingle(clientV1 *fnclient.Fn, clientV2 *v2Client.Fn, buildArgs []stri } } - return DeployFunc(clientV1, buildArgs, verbose, noBump, isLocal, noCache, appName, fpath, ff) + return DeployFunc(clientV1, deployConfig, appName, fpath, ff) } } -func DeployAll(client *fnclient.Fn, buildArgs []string, verbose bool, noBump, isLocal, noCache bool, appDir, appName string, appf *common.AppFile) error { +func DeployAll(client *fnclient.Fn, deployConfig *DeployConfig, appDir, appName string, appf *common.AppFile) error { if appf != nil { err := UpdateAppConfig(client, appf) if err != nil { @@ -111,7 +110,7 @@ func DeployAll(client *fnclient.Fn, buildArgs []string, verbose bool, noBump, is } } - err = DeployFunc(client, buildArgs, verbose, noBump, isLocal, noCache, appName, path, ff) + err = DeployFunc(client, deployConfig, appName, path, ff) if err != nil { return fmt.Errorf("deploy error on %s: %v", path, err) } @@ -132,7 +131,7 @@ func DeployAll(client *fnclient.Fn, buildArgs []string, verbose bool, noBump, is // Parse func.yaml file, bump version, build image, push to registry, and // finally it will update function's route. Optionally, // the route can be overriden inside the func.yaml file. -func DeployFunc(client *fnclient.Fn, buildArgs []string, verbose bool, noBump, isLocal, noCache bool, appName, funcfilePath string, funcfile *common.FuncFile) error { +func DeployFunc(client *fnclient.Fn, deployConfig *DeployConfig, appName, funcfilePath string, funcfile *common.FuncFile) error { dir := filepath.Dir(funcfilePath) // get name from directory if it's not defined if funcfile.Name == "" { @@ -148,7 +147,7 @@ func DeployFunc(client *fnclient.Fn, buildArgs []string, verbose bool, noBump, i } var err error - if !noBump { + if !deployConfig.NoBump { funcfile2, err := common.BumpIt(funcfilePath, common.Patch) if err != nil { return err @@ -158,13 +157,13 @@ func DeployFunc(client *fnclient.Fn, buildArgs []string, verbose bool, noBump, i } // p.noCache - _, err = common.BuildFunc(verbose, funcfilePath, funcfile, buildArgs, noCache) + _, err = common.BuildFunc(deployConfig.BuildArgs, deployConfig.Verbose, deployConfig.NoCache, funcfilePath, funcfile) if err != nil { return err } // p.local - if !isLocal { + if !deployConfig.IsLocal { if err := common.DockerPush(funcfile); err != nil { return err } @@ -173,13 +172,13 @@ func DeployFunc(client *fnclient.Fn, buildArgs []string, verbose bool, noBump, i return updateRoute(client, appName, funcfile) } -func DeployFuncV20180708(clientV1 *fnclient.Fn, clientV2 *v2Client.Fn, buildArgs []string, verbose bool, noBump, isLocal, noCache bool, appName, funcfilePath string, funcfile *common.FuncFileV20180708) error { +func DeployFuncV20180708(clientV1 *fnclient.Fn, clientV2 *v2Client.Fn, deployConfig *DeployConfig, appName, funcfilePath string, funcfile *common.FuncFileV20180708) error { if funcfile.Name == "" { funcfile.Name = filepath.Base(filepath.Dir(funcfilePath)) // todo: should probably make a copy of ff before changing it } var err error - if !noBump { + if !deployConfig.NoBump { funcfile2, err := common.BumpItV20180708(funcfilePath, common.Patch) if err != nil { return err @@ -188,12 +187,13 @@ func DeployFuncV20180708(clientV1 *fnclient.Fn, clientV2 *v2Client.Fn, buildArgs // TODO: this whole funcfile handling needs some love, way too confusing. Only bump makes permanent changes to it. } - _, err = common.BuildFuncV20180708(verbose, funcfilePath, funcfile, buildArgs, noCache) + _, err = common.BuildFuncV20180708(deployConfig.BuildArgs, deployConfig.Verbose, + deployConfig.NoCache, funcfilePath, funcfile) if err != nil { return err } - if !isLocal { + if !deployConfig.IsLocal { if err := common.DockerPushV20180708(funcfile); err != nil { return err } diff --git a/common/common.go b/common/common.go index a766e722..318a9085 100644 --- a/common/common.go +++ b/common/common.go @@ -56,7 +56,7 @@ func GetDir(c *cli.Context) string { } // BuildFunc bumps version and builds function. -func BuildFunc(verbose bool, fpath string, funcfile *FuncFile, buildArg []string, noCache bool) (*FuncFile, error) { +func BuildFunc(buildArg []string, verbose, noCache bool, fpath string, funcfile *FuncFile) (*FuncFile, error) { var err error if funcfile.Version == "" { funcfile, err = BumpIt(fpath, Patch) @@ -77,7 +77,7 @@ func BuildFunc(verbose bool, fpath string, funcfile *FuncFile, buildArg []string } // BuildFunc bumps version and builds function. -func BuildFuncV20180708(verbose bool, fpath string, funcfile *FuncFileV20180708, buildArg []string, noCache bool) (*FuncFileV20180708, error) { +func BuildFuncV20180708(buildArg []string, verbose, noCache bool, fpath string, funcfile *FuncFileV20180708) (*FuncFileV20180708, error) { var err error if funcfile.Version == "" { diff --git a/run/run.go b/run/run.go index 9d320fff..6e9d7690 100644 --- a/run/run.go +++ b/run/run.go @@ -146,7 +146,10 @@ func PreRun(c *cli.Context) (string, *common.FuncFile, []string, error) { } buildArgs := c.StringSlice("build-arg") - _, err = common.BuildFunc(c.GlobalBool("verbose"), fpath, ff, buildArgs, c.Bool("no-cache")) + verbose := c.GlobalBool("verbose") + noCache := c.Bool("no-cache") + + _, err = common.BuildFunc(buildArgs, verbose, noCache, fpath, ff) if err != nil { return fpath, nil, nil, err } @@ -207,7 +210,10 @@ func PreRunV20180708(c *cli.Context) (string, *common.FuncFileV20180708, []strin } buildArgs := c.StringSlice("build-arg") - _, err = common.BuildFuncV20180708(c.GlobalBool("verbose"), fpath, ff, buildArgs, c.Bool("no-cache")) + verbose := c.GlobalBool("verbose") + noCache := c.Bool("no-cache") + + _, err = common.BuildFuncV20180708(buildArgs, verbose, noCache, fpath, ff) if err != nil { return fpath, nil, nil, err } From 1f445339ae9283467094f319d72ff5bb40065212 Mon Sep 17 00:00:00 2001 From: Denis Makogon Date: Sun, 9 Sep 2018 21:14:45 +0300 Subject: [PATCH 4/4] Clean-up --- commands/build.go | 11 +++++------ commands/deploy.go | 8 -------- commands/deploy_api.go | 8 ++++++++ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/commands/build.go b/commands/build.go index 7556da24..aa9aa329 100644 --- a/commands/build.go +++ b/commands/build.go @@ -74,6 +74,9 @@ func (b *buildcmd) build(c *cli.Context) error { return err } + buildArgs := c.StringSlice("build-arg") + verbose := c.GlobalBool("verbose") + switch common.GetFuncYamlVersion(ffV) { case common.LatestYamlVersion: fpath, ff, err := common.FindAndParseFuncFileV20180708(dir) @@ -81,8 +84,7 @@ func (b *buildcmd) build(c *cli.Context) error { return err } - buildArgs := c.StringSlice("build-arg") - ff, err = common.BuildFuncV20180708(buildArgs, c.GlobalBool("verbose"), b.noCache, fpath, ff) + ff, err = common.BuildFuncV20180708(buildArgs, verbose, b.noCache, fpath, ff) if err != nil { return err } @@ -96,10 +98,7 @@ func (b *buildcmd) build(c *cli.Context) error { return err } - buildArgs := c.StringSlice("build-arg") - verbpse := c.GlobalBool("verbose") - - ff, err = common.BuildFunc(buildArgs, verbpse, b.noCache, fpath, ff) + ff, err = common.BuildFunc(buildArgs, verbose, b.noCache, fpath, ff) if err != nil { return err } diff --git a/commands/deploy.go b/commands/deploy.go index fc1e66a0..275de0da 100644 --- a/commands/deploy.go +++ b/commands/deploy.go @@ -155,14 +155,6 @@ func (p *deploycmd) deploy(c *cli.Context) error { return p.deploySingle(c, deployConfig, appName, appf) } -type DeployConfig struct { - BuildArgs []string - Verbose bool - NoBump bool - IsLocal bool - NoCache bool -} - // deploySingle deploys a single function, either the current directory or if in the context // of an app and user provides relative path as the first arg, it will deploy that function. func (p *deploycmd) deploySingle(c *cli.Context, deployConfig *DeployConfig, appName string, appf *common.AppFile) error { diff --git a/commands/deploy_api.go b/commands/deploy_api.go index 3f55e08a..9f9bcd4c 100644 --- a/commands/deploy_api.go +++ b/commands/deploy_api.go @@ -12,6 +12,14 @@ import ( v2Client "github.com/fnproject/fn_go/clientv2" ) +type DeployConfig struct { + BuildArgs []string + Verbose bool + NoBump bool + IsLocal bool + NoCache bool +} + func DeploySingle(clientV1 *fnclient.Fn, clientV2 *v2Client.Fn, deployConfig *DeployConfig, dir, appName string, appf *common.AppFile) error { wd := common.GetWd()