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