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