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