github.com/jenspinney/cli@v6.42.1-0.20190207184520-7450c600020e+incompatible/command/v6/v3_push_original_command.go (about) 1 package v6 2 3 import ( 4 "code.cloudfoundry.org/cli/actor/actionerror" 5 "code.cloudfoundry.org/cli/actor/pushaction" 6 "code.cloudfoundry.org/cli/actor/sharedaction" 7 "code.cloudfoundry.org/cli/actor/v2action" 8 "code.cloudfoundry.org/cli/actor/v3action" 9 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 10 "code.cloudfoundry.org/cli/command" 11 "code.cloudfoundry.org/cli/command/translatableerror" 12 "code.cloudfoundry.org/cli/command/v6/shared" 13 ) 14 15 //go:generate counterfeiter . OriginalV2PushActor 16 17 type OriginalV2PushActor interface { 18 CreateAndMapDefaultApplicationRoute(orgGUID string, spaceGUID string, app v2action.Application) (pushaction.Warnings, error) 19 } 20 21 //go:generate counterfeiter . OriginalV3PushActor 22 23 type OriginalV3PushActor interface { 24 CreateAndUploadBitsPackageByApplicationNameAndSpace(appName string, spaceGUID string, bitsPath string) (v3action.Package, v3action.Warnings, error) 25 CreateDockerPackageByApplicationNameAndSpace(appName string, spaceGUID string, dockerImageCredentials v3action.DockerImageCredentials) (v3action.Package, v3action.Warnings, error) 26 CreateApplicationInSpace(app v3action.Application, spaceGUID string) (v3action.Application, v3action.Warnings, error) 27 GetApplicationByNameAndSpace(appName string, spaceGUID string) (v3action.Application, v3action.Warnings, error) 28 GetApplicationSummaryByNameAndSpace(appName string, spaceGUID string, withObfuscatedValues bool) (v3action.ApplicationSummary, v3action.Warnings, error) 29 GetStreamingLogsForApplicationByNameAndSpace(appName string, spaceGUID string, client v3action.NOAAClient) (<-chan *v3action.LogMessage, <-chan error, v3action.Warnings, error) 30 PollStart(appGUID string, warnings chan<- v3action.Warnings) error 31 SetApplicationDropletByApplicationNameAndSpace(appName string, spaceGUID string, dropletGUID string) (v3action.Warnings, error) 32 StagePackage(packageGUID string, appName string) (<-chan v3action.Droplet, <-chan v3action.Warnings, <-chan error) 33 StartApplication(appGUID string) (v3action.Application, v3action.Warnings, error) 34 StopApplication(appGUID string) (v3action.Warnings, error) 35 UpdateApplication(app v3action.Application) (v3action.Application, v3action.Warnings, error) 36 } 37 38 func (cmd *V3PushCommand) OriginalSetup(config command.Config, ui command.UI) error { 39 cmd.UI = ui 40 cmd.Config = config 41 sharedActor := sharedaction.NewActor(config) 42 43 ccClient, uaaClient, err := shared.NewV3BasedClients(config, ui, true, "") 44 if err != nil { 45 return err 46 } 47 v3actor := v3action.NewActor(ccClient, config, sharedActor, nil) 48 cmd.OriginalActor = v3actor 49 50 ccClientV2, uaaClientV2, err := shared.NewClients(config, ui, true) 51 if err != nil { 52 return err 53 } 54 55 v2Actor := v2action.NewActor(ccClientV2, uaaClientV2, config) 56 57 cmd.SharedActor = sharedActor 58 cmd.OriginalV2PushActor = pushaction.NewActor(v2Actor, v3actor, sharedActor) 59 60 v2AppActor := v2action.NewActor(ccClientV2, uaaClientV2, config) 61 cmd.NOAAClient = shared.NewNOAAClient(ccClient.Info.Logging(), config, uaaClient, ui) 62 63 cmd.AppSummaryDisplayer = shared.AppSummaryDisplayer{ 64 UI: cmd.UI, 65 Config: cmd.Config, 66 Actor: cmd.OriginalActor, 67 V2AppActor: v2AppActor, 68 AppName: cmd.RequiredArgs.AppName, 69 } 70 cmd.PackageDisplayer = shared.NewPackageDisplayer(cmd.UI, cmd.Config) 71 72 return nil 73 } 74 75 func (cmd V3PushCommand) OriginalExecute(args []string) error { 76 cmd.UI.DisplayWarning(command.ExperimentalWarning) 77 78 err := cmd.validateArgs() 79 if err != nil { 80 return err 81 } 82 83 err = cmd.SharedActor.CheckTarget(true, true) 84 if err != nil { 85 return err 86 } 87 88 user, err := cmd.Config.CurrentUser() 89 if err != nil { 90 return err 91 } 92 93 if !verifyBuildpacks(cmd.Buildpacks) { 94 return translatableerror.ConflictingBuildpacksError{} 95 } 96 97 var app v3action.Application 98 app, err = cmd.getApplication() 99 if _, ok := err.(actionerror.ApplicationNotFoundError); ok { 100 app, err = cmd.createApplication(user.Name) 101 if err != nil { 102 return err 103 } 104 } else if err != nil { 105 return err 106 } else { 107 app, err = cmd.updateApplication(user.Name, app.GUID) 108 if err != nil { 109 return err 110 } 111 } 112 113 pkg, err := cmd.createPackage() 114 if err != nil { 115 return err 116 } 117 118 if app.Started() { 119 err = cmd.stopApplication(app.GUID, user.Name) 120 if err != nil { 121 return err 122 } 123 } 124 125 if cmd.NoStart { 126 return nil 127 } 128 129 dropletGUID, err := cmd.stagePackage(pkg, user.Name) 130 if err != nil { 131 return err 132 } 133 134 err = cmd.setApplicationDroplet(dropletGUID, user.Name) 135 if err != nil { 136 return err 137 } 138 139 if !cmd.NoRoute { 140 err = cmd.createAndMapRoutes(app) 141 if err != nil { 142 return err 143 } 144 } 145 146 err = cmd.startApplication(app.GUID, user.Name) 147 if err != nil { 148 return err 149 } 150 151 cmd.UI.DisplayText("Waiting for app to start...") 152 153 warnings := make(chan v3action.Warnings) 154 done := make(chan bool) 155 go func() { 156 for { 157 select { 158 case message := <-warnings: 159 cmd.UI.DisplayWarnings(message) 160 case <-done: 161 return 162 } 163 } 164 }() 165 166 err = cmd.OriginalActor.PollStart(app.GUID, warnings) 167 done <- true 168 169 if err != nil { 170 if _, ok := err.(actionerror.StartupTimeoutError); ok { 171 return translatableerror.StartupTimeoutError{ 172 AppName: cmd.RequiredArgs.AppName, 173 BinaryName: cmd.Config.BinaryName(), 174 } 175 } 176 177 return err 178 } 179 180 cmd.UI.DisplayTextWithFlavor("Showing health and status for app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{ 181 "AppName": cmd.RequiredArgs.AppName, 182 "OrgName": cmd.Config.TargetedOrganization().Name, 183 "SpaceName": cmd.Config.TargetedSpace().Name, 184 "Username": user.Name, 185 }) 186 cmd.UI.DisplayNewline() 187 188 return cmd.AppSummaryDisplayer.DisplayAppInfo() 189 } 190 191 func (cmd V3PushCommand) validateArgs() error { 192 switch { 193 case cmd.DockerImage.Path != "" && cmd.AppPath != "": 194 return translatableerror.ArgumentCombinationError{ 195 Args: []string{"--docker-image", "-o", "-p"}, 196 } 197 case cmd.DockerImage.Path != "" && len(cmd.Buildpacks) > 0: 198 return translatableerror.ArgumentCombinationError{ 199 Args: []string{"-b", "--docker-image", "-o"}, 200 } 201 case cmd.DockerUsername != "" && cmd.DockerImage.Path == "": 202 return translatableerror.RequiredFlagsError{ 203 Arg1: "--docker-image, -o", Arg2: "--docker-username", 204 } 205 case cmd.DockerUsername != "" && cmd.Config.DockerPassword() == "": 206 return translatableerror.DockerPasswordNotSetError{} 207 } 208 return nil 209 } 210 211 func (cmd V3PushCommand) createApplication(userName string) (v3action.Application, error) { 212 appToCreate := v3action.Application{ 213 Name: cmd.RequiredArgs.AppName, 214 } 215 216 if cmd.DockerImage.Path != "" { 217 appToCreate.LifecycleType = constant.AppLifecycleTypeDocker 218 } else { 219 appToCreate.LifecycleType = constant.AppLifecycleTypeBuildpack 220 appToCreate.LifecycleBuildpacks = cmd.Buildpacks 221 } 222 223 app, warnings, err := cmd.OriginalActor.CreateApplicationInSpace( 224 appToCreate, 225 cmd.Config.TargetedSpace().GUID, 226 ) 227 cmd.UI.DisplayWarnings(warnings) 228 if err != nil { 229 return v3action.Application{}, err 230 } 231 232 cmd.UI.DisplayTextWithFlavor("Creating app {{.AppName}} in org {{.CurrentOrg}} / space {{.CurrentSpace}} as {{.CurrentUser}}...", map[string]interface{}{ 233 "AppName": cmd.RequiredArgs.AppName, 234 "CurrentSpace": cmd.Config.TargetedSpace().Name, 235 "CurrentOrg": cmd.Config.TargetedOrganization().Name, 236 "CurrentUser": userName, 237 }) 238 239 cmd.UI.DisplayOK() 240 return app, nil 241 } 242 243 func (cmd V3PushCommand) getApplication() (v3action.Application, error) { 244 app, warnings, err := cmd.OriginalActor.GetApplicationByNameAndSpace(cmd.RequiredArgs.AppName, cmd.Config.TargetedSpace().GUID) 245 cmd.UI.DisplayWarnings(warnings) 246 if err != nil { 247 return v3action.Application{}, err 248 } 249 250 return app, nil 251 } 252 253 func (cmd V3PushCommand) updateApplication(userName string, appGUID string) (v3action.Application, error) { 254 cmd.UI.DisplayTextWithFlavor("Updating app {{.AppName}} in org {{.CurrentOrg}} / space {{.CurrentSpace}} as {{.CurrentUser}}...", map[string]interface{}{ 255 "AppName": cmd.RequiredArgs.AppName, 256 "CurrentSpace": cmd.Config.TargetedSpace().Name, 257 "CurrentOrg": cmd.Config.TargetedOrganization().Name, 258 "CurrentUser": userName, 259 }) 260 261 appToUpdate := v3action.Application{ 262 GUID: appGUID, 263 } 264 265 if cmd.DockerImage.Path != "" { 266 appToUpdate.LifecycleType = constant.AppLifecycleTypeDocker 267 268 } else { 269 appToUpdate.LifecycleType = constant.AppLifecycleTypeBuildpack 270 appToUpdate.LifecycleBuildpacks = cmd.Buildpacks 271 } 272 273 app, warnings, err := cmd.OriginalActor.UpdateApplication(appToUpdate) 274 cmd.UI.DisplayWarnings(warnings) 275 if err != nil { 276 return v3action.Application{}, err 277 } 278 279 cmd.UI.DisplayOK() 280 return app, nil 281 } 282 283 func (cmd V3PushCommand) createAndMapRoutes(app v3action.Application) error { 284 cmd.UI.DisplayText("Mapping routes...") 285 routeWarnings, err := cmd.OriginalV2PushActor.CreateAndMapDefaultApplicationRoute(cmd.Config.TargetedOrganization().GUID, cmd.Config.TargetedSpace().GUID, v2action.Application{Name: app.Name, GUID: app.GUID}) 286 cmd.UI.DisplayWarnings(routeWarnings) 287 if err != nil { 288 return err 289 } 290 291 cmd.UI.DisplayOK() 292 return nil 293 } 294 295 func (cmd V3PushCommand) createPackage() (v3action.Package, error) { 296 isDockerImage := (cmd.DockerImage.Path != "") 297 err := cmd.PackageDisplayer.DisplaySetupMessage(cmd.RequiredArgs.AppName, isDockerImage) 298 if err != nil { 299 return v3action.Package{}, err 300 } 301 302 var ( 303 pkg v3action.Package 304 warnings v3action.Warnings 305 ) 306 307 if isDockerImage { 308 pkg, warnings, err = cmd.OriginalActor.CreateDockerPackageByApplicationNameAndSpace(cmd.RequiredArgs.AppName, cmd.Config.TargetedSpace().GUID, v3action.DockerImageCredentials{Path: cmd.DockerImage.Path, Username: cmd.DockerUsername, Password: cmd.Config.DockerPassword()}) 309 } else { 310 pkg, warnings, err = cmd.OriginalActor.CreateAndUploadBitsPackageByApplicationNameAndSpace(cmd.RequiredArgs.AppName, cmd.Config.TargetedSpace().GUID, string(cmd.AppPath)) 311 } 312 313 cmd.UI.DisplayWarnings(warnings) 314 if err != nil { 315 return v3action.Package{}, err 316 } 317 318 cmd.UI.DisplayOK() 319 return pkg, nil 320 } 321 322 func (cmd V3PushCommand) stagePackage(pkg v3action.Package, userName string) (string, error) { 323 cmd.UI.DisplayTextWithFlavor("Staging package for app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{ 324 "AppName": cmd.RequiredArgs.AppName, 325 "OrgName": cmd.Config.TargetedOrganization().Name, 326 "SpaceName": cmd.Config.TargetedSpace().Name, 327 "Username": userName, 328 }) 329 330 logStream, logErrStream, logWarnings, logErr := cmd.OriginalActor.GetStreamingLogsForApplicationByNameAndSpace(cmd.RequiredArgs.AppName, cmd.Config.TargetedSpace().GUID, cmd.NOAAClient) 331 cmd.UI.DisplayWarnings(logWarnings) 332 if logErr != nil { 333 return "", logErr 334 } 335 336 buildStream, warningsStream, errStream := cmd.OriginalActor.StagePackage(pkg.GUID, cmd.RequiredArgs.AppName) 337 droplet, err := shared.PollStage(buildStream, warningsStream, errStream, logStream, logErrStream, cmd.UI) 338 if err != nil { 339 return "", err 340 } 341 342 cmd.UI.DisplayOK() 343 return droplet.GUID, nil 344 } 345 346 func (cmd V3PushCommand) setApplicationDroplet(dropletGUID string, userName string) error { 347 cmd.UI.DisplayTextWithFlavor("Setting app {{.AppName}} to droplet {{.DropletGUID}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{ 348 "AppName": cmd.RequiredArgs.AppName, 349 "DropletGUID": dropletGUID, 350 "OrgName": cmd.Config.TargetedOrganization().Name, 351 "SpaceName": cmd.Config.TargetedSpace().Name, 352 "Username": userName, 353 }) 354 355 warnings, err := cmd.OriginalActor.SetApplicationDropletByApplicationNameAndSpace(cmd.RequiredArgs.AppName, cmd.Config.TargetedSpace().GUID, dropletGUID) 356 cmd.UI.DisplayWarnings(warnings) 357 if err != nil { 358 return err 359 } 360 361 cmd.UI.DisplayOK() 362 return nil 363 } 364 365 func (cmd V3PushCommand) startApplication(appGUID string, userName string) error { 366 cmd.UI.DisplayTextWithFlavor("Starting app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...", map[string]interface{}{ 367 "AppName": cmd.RequiredArgs.AppName, 368 "OrgName": cmd.Config.TargetedOrganization().Name, 369 "SpaceName": cmd.Config.TargetedSpace().Name, 370 "Username": userName, 371 }) 372 373 _, warnings, err := cmd.OriginalActor.StartApplication(appGUID) 374 cmd.UI.DisplayWarnings(warnings) 375 if err != nil { 376 return err 377 } 378 cmd.UI.DisplayOK() 379 return nil 380 } 381 382 func (cmd V3PushCommand) stopApplication(appGUID string, userName string) error { 383 cmd.UI.DisplayTextWithFlavor("Stopping app {{.AppName}} in org {{.CurrentOrg}} / space {{.CurrentSpace}} as {{.CurrentUser}}...", map[string]interface{}{ 384 "AppName": cmd.RequiredArgs.AppName, 385 "CurrentSpace": cmd.Config.TargetedSpace().Name, 386 "CurrentOrg": cmd.Config.TargetedOrganization().Name, 387 "CurrentUser": userName, 388 }) 389 390 warnings, err := cmd.OriginalActor.StopApplication(appGUID) 391 cmd.UI.DisplayWarnings(warnings) 392 if err != nil { 393 return err 394 } 395 cmd.UI.DisplayOK() 396 cmd.UI.DisplayNewline() 397 return nil 398 } 399 400 func verifyBuildpacks(buildpacks []string) bool { 401 if len(buildpacks) < 2 { 402 return true 403 } 404 405 for _, buildpack := range buildpacks { 406 if buildpack == "default" || buildpack == "null" { 407 return false 408 } 409 } 410 return true 411 }