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