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