github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/command/v6/v3_scale_command.go (about)

     1  package v6
     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/v3action"
     8  	"code.cloudfoundry.org/cli/command"
     9  	"code.cloudfoundry.org/cli/command/flag"
    10  	"code.cloudfoundry.org/cli/command/translatableerror"
    11  	"code.cloudfoundry.org/cli/command/v6/shared"
    12  )
    13  
    14  //go:generate counterfeiter . V3ScaleActor
    15  
    16  type V3ScaleActor interface {
    17  	shared.V3AppSummaryActor
    18  
    19  	GetApplicationByNameAndSpace(appName string, spaceGUID string) (v3action.Application, v3action.Warnings, error)
    20  	ScaleProcessByApplication(appGUID string, process v3action.Process) (v3action.Warnings, error)
    21  	StopApplication(appGUID string) (v3action.Warnings, error)
    22  	StartApplication(appGUID string) (v3action.Warnings, error)
    23  	PollStart(appGUID string, warnings chan<- v3action.Warnings) error
    24  }
    25  
    26  type V3ScaleCommand 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 v3-scale APP_NAME [--process PROCESS] [-i INSTANCES] [-k DISK] [-m MEMORY]"`
    34  	relatedCommands     interface{}    `related_commands:"v3-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               V3ScaleActor
    40  	SharedActor         command.SharedActor
    41  	AppSummaryDisplayer shared.AppSummaryDisplayer
    42  }
    43  
    44  func (cmd *V3ScaleCommand) Setup(config command.Config, ui command.UI) error {
    45  	cmd.UI = ui
    46  	cmd.Config = config
    47  	cmd.SharedActor = sharedaction.NewActor(config)
    48  
    49  	ccClient, _, err := shared.NewV3BasedClients(config, ui, true)
    50  	if err != nil {
    51  		return err
    52  	}
    53  	cmd.Actor = v3action.NewActor(ccClient, config, nil, nil)
    54  
    55  	ccClientV2, uaaClientV2, err := shared.GetNewClientsAndConnectToCF(config, ui)
    56  	if err != nil {
    57  		return err
    58  	}
    59  	v2Actor := v2action.NewActor(ccClientV2, uaaClientV2, config)
    60  
    61  	cmd.AppSummaryDisplayer = shared.AppSummaryDisplayer{
    62  		UI:         ui,
    63  		Config:     config,
    64  		Actor:      cmd.Actor,
    65  		V2AppActor: v2Actor,
    66  		AppName:    cmd.RequiredArgs.AppName,
    67  	}
    68  
    69  	return nil
    70  }
    71  
    72  func (cmd V3ScaleCommand) Execute(args []string) error {
    73  	cmd.UI.DisplayWarning(command.ExperimentalWarning)
    74  
    75  	err := cmd.SharedActor.CheckTarget(true, true)
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	user, err := cmd.Config.CurrentUser()
    81  	if err != nil {
    82  		return err
    83  	}
    84  
    85  	app, warnings, err := cmd.Actor.GetApplicationByNameAndSpace(cmd.RequiredArgs.AppName, cmd.Config.TargetedSpace().GUID)
    86  	cmd.UI.DisplayWarnings(warnings)
    87  	if err != nil {
    88  		return err
    89  	}
    90  
    91  	if !cmd.Instances.IsSet && !cmd.DiskLimit.IsSet && !cmd.MemoryLimit.IsSet {
    92  		return cmd.showCurrentScale(user.Name)
    93  	}
    94  
    95  	scalled, err := cmd.scaleProcess(app.GUID, user.Name)
    96  	if err != nil {
    97  		return err
    98  	}
    99  	if !scalled {
   100  		return nil
   101  	}
   102  
   103  	pollWarnings := make(chan v3action.Warnings)
   104  	done := make(chan bool)
   105  	go func() {
   106  		for {
   107  			select {
   108  			case message := <-pollWarnings:
   109  				cmd.UI.DisplayWarnings(message)
   110  			case <-done:
   111  				return
   112  			}
   113  		}
   114  	}()
   115  
   116  	err = cmd.Actor.PollStart(app.GUID, pollWarnings)
   117  	done <- true
   118  
   119  	if err != nil {
   120  		if _, ok := err.(actionerror.StartupTimeoutError); ok {
   121  			return translatableerror.StartupTimeoutError{
   122  				AppName:    cmd.RequiredArgs.AppName,
   123  				BinaryName: cmd.Config.BinaryName(),
   124  			}
   125  		}
   126  
   127  		return err
   128  	}
   129  
   130  	return cmd.showCurrentScale(user.Name)
   131  }
   132  
   133  func (cmd V3ScaleCommand) scaleProcess(appGUID string, username string) (bool, error) {
   134  	cmd.UI.DisplayTextWithFlavor("Scaling app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{
   135  		"AppName":   cmd.RequiredArgs.AppName,
   136  		"OrgName":   cmd.Config.TargetedOrganization().Name,
   137  		"SpaceName": cmd.Config.TargetedSpace().Name,
   138  		"Username":  username,
   139  	})
   140  	cmd.UI.DisplayNewline()
   141  
   142  	shouldRestart := cmd.DiskLimit.IsSet || cmd.MemoryLimit.IsSet
   143  	if shouldRestart && !cmd.Force {
   144  		shouldScale, err := cmd.UI.DisplayBoolPrompt(
   145  			false,
   146  			"This will cause the app to restart. Are you sure you want to scale {{.AppName}}?",
   147  			map[string]interface{}{"AppName": cmd.RequiredArgs.AppName})
   148  		if err != nil {
   149  			return false, err
   150  		}
   151  
   152  		if !shouldScale {
   153  			cmd.UI.DisplayText("Scaling cancelled")
   154  			return false, nil
   155  		}
   156  		cmd.UI.DisplayNewline()
   157  	}
   158  
   159  	warnings, err := cmd.Actor.ScaleProcessByApplication(appGUID, v3action.Process{
   160  		Type:       cmd.ProcessType,
   161  		Instances:  cmd.Instances.NullInt,
   162  		MemoryInMB: cmd.MemoryLimit.NullUint64,
   163  		DiskInMB:   cmd.DiskLimit.NullUint64,
   164  	})
   165  	cmd.UI.DisplayWarnings(warnings)
   166  	if err != nil {
   167  		return false, err
   168  	}
   169  
   170  	if shouldRestart {
   171  		err := cmd.restartApplication(appGUID, username)
   172  		if err != nil {
   173  			return false, err
   174  		}
   175  	}
   176  
   177  	return true, nil
   178  }
   179  
   180  func (cmd V3ScaleCommand) restartApplication(appGUID string, username string) error {
   181  	cmd.UI.DisplayTextWithFlavor("Stopping app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{
   182  		"AppName":   cmd.RequiredArgs.AppName,
   183  		"OrgName":   cmd.Config.TargetedOrganization().Name,
   184  		"SpaceName": cmd.Config.TargetedSpace().Name,
   185  		"Username":  username,
   186  	})
   187  	cmd.UI.DisplayNewline()
   188  
   189  	warnings, err := cmd.Actor.StopApplication(appGUID)
   190  	cmd.UI.DisplayWarnings(warnings)
   191  	if err != nil {
   192  		return err
   193  	}
   194  
   195  	cmd.UI.DisplayTextWithFlavor("Starting app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{
   196  		"AppName":   cmd.RequiredArgs.AppName,
   197  		"OrgName":   cmd.Config.TargetedOrganization().Name,
   198  		"SpaceName": cmd.Config.TargetedSpace().Name,
   199  		"Username":  username,
   200  	})
   201  	cmd.UI.DisplayNewline()
   202  
   203  	warnings, err = cmd.Actor.StartApplication(appGUID)
   204  	cmd.UI.DisplayWarnings(warnings)
   205  	if err != nil {
   206  		return err
   207  	}
   208  
   209  	return nil
   210  }
   211  
   212  func (cmd V3ScaleCommand) showCurrentScale(userName string) error {
   213  	cmd.UI.DisplayTextWithFlavor("Showing current scale of app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{
   214  		"AppName":   cmd.RequiredArgs.AppName,
   215  		"OrgName":   cmd.Config.TargetedOrganization().Name,
   216  		"SpaceName": cmd.Config.TargetedSpace().Name,
   217  		"Username":  userName,
   218  	})
   219  
   220  	return cmd.AppSummaryDisplayer.DisplayAppProcessInfo()
   221  }