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  }