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