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 }