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