github.com/franc20/ayesa_sap@v7.0.0-beta.28.0.20200124003224-302d4d52fa6c+incompatible/command/v7/scale_command.go (about)

     1  package v7
     2  
     3  import (
     4  	"code.cloudfoundry.org/cli/actor/actionerror"
     5  	"code.cloudfoundry.org/cli/actor/sharedaction"
     6  	"code.cloudfoundry.org/cli/actor/v7action"
     7  	"code.cloudfoundry.org/cli/command"
     8  	"code.cloudfoundry.org/cli/command/flag"
     9  	"code.cloudfoundry.org/cli/command/translatableerror"
    10  	"code.cloudfoundry.org/cli/command/v7/shared"
    11  	"code.cloudfoundry.org/clock"
    12  )
    13  
    14  //go:generate counterfeiter . ScaleActor
    15  
    16  type ScaleActor interface {
    17  	AppActor
    18  
    19  	ScaleProcessByApplication(appGUID string, process v7action.Process) (v7action.Warnings, error)
    20  	StopApplication(appGUID string) (v7action.Warnings, error)
    21  	StartApplication(appGUID string) (v7action.Warnings, error)
    22  	PollStart(appGUID string, noWait bool) (v7action.Warnings, error)
    23  }
    24  
    25  type ScaleCommand struct {
    26  	RequiredArgs        flag.AppName   `positional-args:"yes"`
    27  	Force               bool           `short:"f" description:"Force restart of app without prompt"`
    28  	Instances           flag.Instances `short:"i" required:"false" description:"Number of instances"`
    29  	DiskLimit           flag.Megabytes `short:"k" required:"false" description:"Disk limit (e.g. 256M, 1024M, 1G)"`
    30  	MemoryLimit         flag.Megabytes `short:"m" required:"false" description:"Memory limit (e.g. 256M, 1024M, 1G)"`
    31  	ProcessType         string         `long:"process" default:"web" description:"App process to scale"`
    32  	usage               interface{}    `usage:"CF_NAME scale APP_NAME [--process PROCESS] [-i INSTANCES] [-k DISK] [-m MEMORY] [-f]"`
    33  	relatedCommands     interface{}    `related_commands:"push"`
    34  	envCFStartupTimeout interface{}    `environmentName:"CF_STARTUP_TIMEOUT" environmentDescription:"Max wait time for app instance startup, in minutes" environmentDefault:"5"`
    35  
    36  	UI          command.UI
    37  	Config      command.Config
    38  	Actor       ScaleActor
    39  	SharedActor command.SharedActor
    40  }
    41  
    42  func (cmd *ScaleCommand) Setup(config command.Config, ui command.UI) error {
    43  	cmd.UI = ui
    44  	cmd.Config = config
    45  	sharedActor := sharedaction.NewActor(config)
    46  	cmd.SharedActor = sharedActor
    47  
    48  	ccClient, uaaClient, err := shared.GetNewClientsAndConnectToCF(config, ui, "")
    49  	if err != nil {
    50  		return err
    51  	}
    52  	cmd.Actor = v7action.NewActor(ccClient, config, sharedActor, uaaClient, clock.NewClock())
    53  
    54  	return nil
    55  }
    56  
    57  func (cmd ScaleCommand) Execute(args []string) error {
    58  	err := cmd.SharedActor.CheckTarget(true, true)
    59  	if err != nil {
    60  		return err
    61  	}
    62  
    63  	user, err := cmd.Config.CurrentUser()
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	app, warnings, err := cmd.Actor.GetApplicationByNameAndSpace(cmd.RequiredArgs.AppName, cmd.Config.TargetedSpace().GUID)
    69  	cmd.UI.DisplayWarnings(warnings)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	if !cmd.Instances.IsSet && !cmd.DiskLimit.IsSet && !cmd.MemoryLimit.IsSet {
    75  		return cmd.showCurrentScale(user.Name, err)
    76  	}
    77  
    78  	scaled, err := cmd.scaleProcess(app.GUID, user.Name)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	if !scaled {
    83  		return nil
    84  	}
    85  
    86  	warnings, err = cmd.Actor.PollStart(app.GUID, false)
    87  	cmd.UI.DisplayWarnings(warnings)
    88  
    89  	showErr := cmd.showCurrentScale(user.Name, err)
    90  	if showErr != nil {
    91  		return showErr
    92  	}
    93  
    94  	return cmd.translateErrors(err)
    95  }
    96  
    97  func (cmd ScaleCommand) translateErrors(err error) error {
    98  	if _, ok := err.(actionerror.StartupTimeoutError); ok {
    99  		return translatableerror.StartupTimeoutError{
   100  			AppName:    cmd.RequiredArgs.AppName,
   101  			BinaryName: cmd.Config.BinaryName(),
   102  		}
   103  	} else if _, ok := err.(actionerror.AllInstancesCrashedError); ok {
   104  		return translatableerror.ApplicationUnableToStartError{
   105  			AppName:    cmd.RequiredArgs.AppName,
   106  			BinaryName: cmd.Config.BinaryName(),
   107  		}
   108  	}
   109  
   110  	return err
   111  }
   112  
   113  func (cmd ScaleCommand) scaleProcess(appGUID string, username string) (bool, error) {
   114  	cmd.UI.DisplayTextWithFlavor("Scaling app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{
   115  		"AppName":   cmd.RequiredArgs.AppName,
   116  		"OrgName":   cmd.Config.TargetedOrganization().Name,
   117  		"SpaceName": cmd.Config.TargetedSpace().Name,
   118  		"Username":  username,
   119  	})
   120  	cmd.UI.DisplayNewline()
   121  
   122  	shouldRestart := cmd.DiskLimit.IsSet || cmd.MemoryLimit.IsSet
   123  	if shouldRestart && !cmd.Force {
   124  		shouldScale, err := cmd.UI.DisplayBoolPrompt(
   125  			false,
   126  			"This will cause the app to restart. Are you sure you want to scale {{.AppName}}?",
   127  			map[string]interface{}{"AppName": cmd.RequiredArgs.AppName})
   128  		if err != nil {
   129  			return false, err
   130  		}
   131  
   132  		if !shouldScale {
   133  			cmd.UI.DisplayText("Scaling cancelled")
   134  			return false, nil
   135  		}
   136  		cmd.UI.DisplayNewline()
   137  	}
   138  
   139  	warnings, err := cmd.Actor.ScaleProcessByApplication(appGUID, v7action.Process{
   140  		Type:       cmd.ProcessType,
   141  		Instances:  cmd.Instances.NullInt,
   142  		MemoryInMB: cmd.MemoryLimit.NullUint64,
   143  		DiskInMB:   cmd.DiskLimit.NullUint64,
   144  	})
   145  	cmd.UI.DisplayWarnings(warnings)
   146  	if err != nil {
   147  		return false, err
   148  	}
   149  
   150  	if shouldRestart {
   151  		err := cmd.restartApplication(appGUID, username)
   152  		if err != nil {
   153  			return false, err
   154  		}
   155  	}
   156  
   157  	return true, nil
   158  }
   159  
   160  func (cmd ScaleCommand) restartApplication(appGUID string, username string) error {
   161  	cmd.UI.DisplayTextWithFlavor("Stopping app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{
   162  		"AppName":   cmd.RequiredArgs.AppName,
   163  		"OrgName":   cmd.Config.TargetedOrganization().Name,
   164  		"SpaceName": cmd.Config.TargetedSpace().Name,
   165  		"Username":  username,
   166  	})
   167  	cmd.UI.DisplayNewline()
   168  
   169  	warnings, err := cmd.Actor.StopApplication(appGUID)
   170  	cmd.UI.DisplayWarnings(warnings)
   171  	if err != nil {
   172  		return err
   173  	}
   174  
   175  	cmd.UI.DisplayTextWithFlavor("Starting app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{
   176  		"AppName":   cmd.RequiredArgs.AppName,
   177  		"OrgName":   cmd.Config.TargetedOrganization().Name,
   178  		"SpaceName": cmd.Config.TargetedSpace().Name,
   179  		"Username":  username,
   180  	})
   181  	cmd.UI.DisplayNewline()
   182  
   183  	warnings, err = cmd.Actor.StartApplication(appGUID)
   184  	cmd.UI.DisplayWarnings(warnings)
   185  	if err != nil {
   186  		return err
   187  	}
   188  
   189  	return nil
   190  }
   191  
   192  func (cmd ScaleCommand) showCurrentScale(userName string, runningErr error) error {
   193  	if !shouldShowCurrentScale(runningErr) {
   194  		return nil
   195  	}
   196  
   197  	cmd.UI.DisplayTextWithFlavor("Showing current scale of app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{
   198  		"AppName":   cmd.RequiredArgs.AppName,
   199  		"OrgName":   cmd.Config.TargetedOrganization().Name,
   200  		"SpaceName": cmd.Config.TargetedSpace().Name,
   201  		"Username":  userName,
   202  	})
   203  
   204  	summary, warnings, err := cmd.Actor.GetDetailedAppSummary(cmd.RequiredArgs.AppName, cmd.Config.TargetedSpace().GUID, false)
   205  	cmd.UI.DisplayWarnings(warnings)
   206  	if err != nil {
   207  		return err
   208  	}
   209  
   210  	appSummaryDisplayer := shared.NewAppSummaryDisplayer(cmd.UI)
   211  	appSummaryDisplayer.AppDisplay(summary, false)
   212  	return nil
   213  }
   214  
   215  func shouldShowCurrentScale(err error) bool {
   216  	if err == nil {
   217  		return true
   218  	}
   219  
   220  	if _, ok := err.(actionerror.AllInstancesCrashedError); ok {
   221  		return true
   222  	}
   223  
   224  	return false
   225  }