Skip to content

Commit

Permalink
Updated account link to use staged deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
akclace committed Feb 15, 2024
1 parent 31741f7 commit fd92acd
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 118 deletions.
31 changes: 22 additions & 9 deletions cmd/clace/account_cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,44 +28,57 @@ func accountLinkCommand(commonFlags []cli.Flag, clientConfig *utils.ClientConfig
flags := make([]cli.Flag, 0, len(commonFlags)+2)
flags = append(flags, commonFlags...)
flags = append(flags, dryRunFlag())
flags = append(flags, newBoolFlag(PROMOTE_FLAG, "p", "Promote the change from stage to prod", false))

return &cli.Command{
Name: "link",
Usage: "Link an app to to use specific account for a plugin",
Flags: flags,
Before: altsrc.InitInputSourceWithContext(flags, altsrc.NewTomlSourceFromFlagFunc(configFileFlagName)),
ArgsUsage: "<appPath> <pluginName> <accountName>",
UsageText: `args: <appPath> <pluginName> <accountName>
ArgsUsage: "<pathSpec> <pluginName> <accountName>",
UsageText: `args: <pathSpec> <pluginName> <accountName>
<app_path> is a required first argument. The optional domain and path are separated by a ":". This is the app for which the account link is to be created.
<pluginName> is the required second argument. This is the name of the plugin.
<accountName> is the required third argument. This is the name of the account to link to the plugin.
<pathSpec> is the first required argument. ` + PATH_SPEC_HELP + `<pluginName> is the required second argument. This is the name of the plugin.
<accountName> is the required third argument. This is the name of the account to link to for the plugin. Use "-" to unlink the existing account.
Examples:
Link db plugin: clace account link /myapp db.in temp
Link in dryrun mode: clace account link --dry-run example.com:/ rest.in testaccount`,
Action: func(cCtx *cli.Context) error {
if cCtx.NArg() != 3 {
return fmt.Errorf("requires three arguments: <appPath> <pluginName> <accountName>")
return fmt.Errorf("requires three arguments: <pathSpec> <pluginName> <accountName>")
}

client := utils.NewHttpClient(clientConfig.ServerUri, clientConfig.AdminUser, clientConfig.AdminPassword, clientConfig.SkipCertCheck)
values := url.Values{}
values.Add("appPath", cCtx.Args().First())
values.Add("pathSpec", cCtx.Args().First())
values.Add("plugin", cCtx.Args().Get(1))
values.Add("account", cCtx.Args().Get(2))
values.Add(DRY_RUN_ARG, strconv.FormatBool(cCtx.Bool(DRY_RUN_FLAG)))
values.Add(PROMOTE_ARG, strconv.FormatBool(cCtx.Bool(PROMOTE_FLAG)))

var linkResponse utils.AppLinkAccountResponse
err := client.Post("/_clace/link_account", values, nil, &linkResponse)
if err != nil {
return err
}

for _, linkedApp := range linkResponse.LinkResults {
for _, linkedApp := range linkResponse.StagedUpdateResults {
fmt.Printf("Linked app %s\n", linkedApp)
}
fmt.Fprintf(cCtx.App.Writer, "%d app(s) linked, 0 app(s) promoted.\n", len(linkResponse.LinkResults))

if len(linkResponse.PromoteResults) > 0 {
fmt.Fprintf(cCtx.App.Writer, "Promoted apps: ")
for i, promoteResult := range linkResponse.PromoteResults {
if i > 0 {
fmt.Fprintf(cCtx.App.Writer, ", ")
}
fmt.Fprintf(cCtx.App.Writer, "%s", promoteResult)
}
fmt.Fprintln(cCtx.App.Writer)
}

fmt.Fprintf(cCtx.App.Writer, "%d app(s) linked, %d app(s) promoted.\n", len(linkResponse.StagedUpdateResults), len(linkResponse.PromoteResults))

if linkResponse.DryRun {
fmt.Print(DRY_RUN_MESSAGE)
Expand Down
6 changes: 3 additions & 3 deletions internal/server/app_apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ func (s *Server) auditApp(ctx context.Context, tx metadata.Transaction, app *app
return auditResult, nil
}

func (s *Server) CompleteTransaction(ctx context.Context, tx metadata.Transaction, apps []*app.App, dryRun bool) error {
func (s *Server) CompleteTransaction(ctx context.Context, tx metadata.Transaction, entries []utils.AppPathDomain, dryRun bool) error {
if dryRun {
return nil
}
Expand All @@ -478,8 +478,8 @@ func (s *Server) CompleteTransaction(ctx context.Context, tx metadata.Transactio
}

// Update the in memory cache
if apps != nil {
s.apps.UpdateApps(apps)
if entries != nil {
s.apps.DeleteApps(entries)
}
return nil
}
Expand Down
101 changes: 24 additions & 77 deletions internal/server/app_updates.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"context"
"fmt"
"net/http"
"strings"

"github.com/claceio/clace/internal/app"
"github.com/claceio/clace/internal/metadata"
Expand Down Expand Up @@ -111,9 +110,6 @@ func (s *Server) ReloadApps(ctx context.Context, pathSpec string, approve, dryRu
}
}

prodApps := make([]*app.App, 0, len(filteredApps))
devApps := make([]*app.App, 0, len(filteredApps))

for _, stageApp := range stageApps {
if _, err := stageApp.Reload(true, true); err != nil {
return nil, fmt.Errorf("error reloading stage app %s: %w", stageApp.AppEntry, err)
Expand All @@ -126,10 +122,11 @@ func (s *Server) ReloadApps(ctx context.Context, pathSpec string, approve, dryRu
if err != nil {
return nil, fmt.Errorf("error setting up prod app %s: %w", prodAppEntry, err)
}
prodApps = append(prodApps, prodApp)
if _, err := prodApp.Reload(true, true); err != nil {
return nil, fmt.Errorf("error reloading prod app %s: %w", prodApp.AppEntry, err)
}

reloadResults = append(reloadResults, prodAppEntry.AppPathDomain())
}
}

Expand All @@ -139,7 +136,6 @@ func (s *Server) ReloadApps(ctx context.Context, pathSpec string, approve, dryRu
return nil, fmt.Errorf("error setting up app %s: %w", devAppEntry, err)
}
reloadResults = append(reloadResults, devAppEntry.AppPathDomain())
devApps = append(devApps, devApp)

devResult, err := devApp.Audit()
if err != nil {
Expand All @@ -164,15 +160,8 @@ func (s *Server) ReloadApps(ctx context.Context, pathSpec string, approve, dryRu
}
}

updatedApps := make([]*app.App, 0, len(stageApps)+len(prodApps)+len(devApps))
updatedApps = append(updatedApps, devApps...)
updatedApps = append(updatedApps, stageApps...)
if promote {
updatedApps = append(updatedApps, prodApps...)
}

// Commit the transaction if not dry run and update the in memory app store
if err := s.CompleteTransaction(ctx, tx, updatedApps, dryRun); err != nil {
if err := s.CompleteTransaction(ctx, tx, reloadResults, dryRun); err != nil {
return nil, err
}

Expand Down Expand Up @@ -211,7 +200,7 @@ func (s *Server) StagedUpdate(ctx context.Context, pathSpec string, dryRun, prom
}
defer tx.Rollback()

result, promoteResults, apps, err := s.StagedUpdateAppsTx(ctx, tx, pathSpec, promote, handler, args)
result, entries, promoteResults, err := s.StagedUpdateAppsTx(ctx, tx, pathSpec, promote, handler, args)
if err != nil {
return nil, err
}
Expand All @@ -222,23 +211,23 @@ func (s *Server) StagedUpdate(ctx context.Context, pathSpec string, dryRun, prom
PromoteResults: promoteResults,
}

if err := s.CompleteTransaction(ctx, tx, apps, dryRun); err != nil {
if err := s.CompleteTransaction(ctx, tx, entries, dryRun); err != nil {
return nil, err
}

return ret, nil
}

type stagedUpdateHandler func(ctx context.Context, tx metadata.Transaction, appEntry *utils.AppEntry, args map[string]any) (any, *app.App, error)
type stagedUpdateHandler func(ctx context.Context, tx metadata.Transaction, appEntry *utils.AppEntry, args map[string]any) (any, utils.AppPathDomain, error)

func (s *Server) StagedUpdateAppsTx(ctx context.Context, tx metadata.Transaction, pathSpec string, promote bool, handler stagedUpdateHandler, args map[string]any) ([]any, []utils.AppPathDomain, []*app.App, error) {
func (s *Server) StagedUpdateAppsTx(ctx context.Context, tx metadata.Transaction, pathSpec string, promote bool, handler stagedUpdateHandler, args map[string]any) ([]any, []utils.AppPathDomain, []utils.AppPathDomain, error) {
filteredApps, err := s.FilterApps(pathSpec, false)
if err != nil {
return nil, nil, nil, err
}

results := make([]any, 0, len(filteredApps))
apps := make([]*app.App, 0, len(filteredApps))
entries := make([]utils.AppPathDomain, 0, len(filteredApps))
promoteResults := make([]utils.AppPathDomain, 0, len(filteredApps))
for _, appInfo := range filteredApps {
appEntry, err := s.GetAppEntry(ctx, tx, appInfo.AppPathDomain)
Expand All @@ -248,7 +237,7 @@ func (s *Server) StagedUpdateAppsTx(ctx context.Context, tx metadata.Transaction

var prodAppEntry *utils.AppEntry
if !appEntry.IsDev {
// For prod apps, approve the staging app
// For prod apps, update the staging app
prodAppEntry = appEntry
appEntry, err = s.getStageApp(ctx, tx, appEntry)
if err != nil {
Expand Down Expand Up @@ -283,29 +272,30 @@ func (s *Server) StagedUpdateAppsTx(ctx context.Context, tx metadata.Transaction
if err != nil {
return nil, nil, nil, fmt.Errorf("error setting up prod app %s: %w", prodAppEntry, err)
}
apps = append(apps, prodApp)
entries = append(entries, prodApp.AppPathDomain())
promoteResults = append(promoteResults, prodAppEntry.AppPathDomain())
}
}

apps = append(apps, app)
entries = append(entries, app)
results = append(results, result)
}

return results, promoteResults, apps, nil
return results, entries, promoteResults, nil
}

func (s *Server) auditHandler(ctx context.Context, tx metadata.Transaction, appEntry *utils.AppEntry, args map[string]any) (any, *app.App, error) {
func (s *Server) auditHandler(ctx context.Context, tx metadata.Transaction, appEntry *utils.AppEntry, args map[string]any) (any, utils.AppPathDomain, error) {
appPathDomain := appEntry.AppPathDomain()
app, err := s.setupApp(appEntry, tx)
if err != nil {
return nil, nil, err
return nil, appPathDomain, err
}
result, err := s.auditApp(ctx, tx, app, true)
if err != nil {
return nil, nil, err
return nil, appPathDomain, err
}

return result, app, nil
return result, appPathDomain, nil
}

func (s *Server) PromoteApps(ctx context.Context, pathSpec string, dryRun bool) (*utils.AppPromoteResponse, error) {
Expand All @@ -321,7 +311,6 @@ func (s *Server) PromoteApps(ctx context.Context, pathSpec string, dryRun bool)
defer tx.Rollback()

result := make([]utils.AppPathDomain, 0, len(filteredApps))
newApps := make([]*app.App, 0, len(filteredApps))
for _, appInfo := range filteredApps {
if appInfo.IsDev {
// Not a prod app, skip
Expand Down Expand Up @@ -353,11 +342,10 @@ func (s *Server) PromoteApps(ctx context.Context, pathSpec string, dryRun bool)
if _, err := prodApp.Reload(true, true); err != nil {
return nil, fmt.Errorf("error reloading prod app %s: %w", prodApp.AppEntry, err)
}
newApps = append(newApps, prodApp)
result = append(result, appInfo.AppPathDomain)
}

if err = s.CompleteTransaction(ctx, tx, newApps, dryRun); err != nil {
if err = s.CompleteTransaction(ctx, tx, result, dryRun); err != nil {
return nil, err
}

Expand All @@ -368,7 +356,6 @@ func (s *Server) PromoteApps(ctx context.Context, pathSpec string, dryRun bool)

func (s *Server) promoteApp(ctx context.Context, tx metadata.Transaction, stagingApp *utils.AppEntry, prodApp *utils.AppEntry) (bool, error) {
stagingFileStore := metadata.NewFileStore(stagingApp.Id, stagingApp.Metadata.VersionMetadata.Version, s.db, tx)

prevVersion := prodApp.Metadata.VersionMetadata.Version
newVersion := stagingApp.Metadata.VersionMetadata.Version

Expand Down Expand Up @@ -493,36 +480,14 @@ func (s *Server) updateAppSettings(ctx context.Context, tx metadata.Transaction,
return ret, nil
}

func (s *Server) LinkAccount(ctx context.Context, mainAppPath, plugin, account string, dryRun bool) (*utils.AppLinkAccountResponse, error) {
mainAppPathDomain, err := parseAppPath(mainAppPath)
if err != nil {
return nil, err
}

tx, err := s.db.BeginTransaction(ctx)
if err != nil {
return nil, err
}
defer tx.Rollback()

mainAppEntry, err := s.db.GetAppTx(ctx, tx, mainAppPathDomain)
if err != nil {
return nil, err
}

appEntry := mainAppEntry
if strings.HasPrefix(string(mainAppEntry.Id), utils.ID_PREFIX_APP_PROD) {
// For prod app, update the staging app
appEntry, err = s.getStageApp(ctx, tx, mainAppEntry)
if err != nil {
return nil, err
}
}

func (s *Server) accountLinkHandler(ctx context.Context, tx metadata.Transaction, appEntry *utils.AppEntry, args map[string]any) (any, utils.AppPathDomain, error) {
if appEntry.Metadata.Accounts == nil {
appEntry.Metadata.Accounts = []utils.AccountLink{}
}

plugin := args["plugin"].(string)
account := args["account"].(string)

matchIndex := -1
for i, accountLink := range appEntry.Metadata.Accounts {
if accountLink.Plugin == plugin {
Expand All @@ -548,24 +513,6 @@ func (s *Server) LinkAccount(ctx context.Context, mainAppPath, plugin, account s
}
}

// Persist the updated metadata
if err := s.db.UpdateAppMetadata(ctx, tx, appEntry); err != nil {
return nil, err
}

ret := &utils.AppLinkAccountResponse{
DryRun: dryRun,
LinkResults: []utils.AppPathDomain{appEntry.AppPathDomain()},
}

if dryRun {
return ret, nil
}

if err = tx.Commit(); err != nil {
return nil, err
}

s.apps.DeleteApps(ret.LinkResults) // Delete from in memory cache
return ret, nil
appPathDomain := appEntry.AppPathDomain()
return appPathDomain, appPathDomain, nil
}
Loading

0 comments on commit fd92acd

Please sign in to comment.