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