github.com/sleungcy/cli@v7.1.0+incompatible/command/v7/shared/app_stager.go (about)

     1  package shared
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"code.cloudfoundry.org/cli/actor/sharedaction"
     8  	"code.cloudfoundry.org/cli/actor/v7action"
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    10  	"code.cloudfoundry.org/cli/command"
    11  	"code.cloudfoundry.org/cli/resources"
    12  	"code.cloudfoundry.org/cli/util/configv3"
    13  )
    14  
    15  /*
    16  	AppStager interface extracts the complexity of the asynchronous
    17      staging process, which is used by several commands (e.g. restage,
    18      copy-package).
    19  */
    20  
    21  //go:generate counterfeiter . AppStager
    22  
    23  type AppStager interface {
    24  	StageAndStart(
    25  		app resources.Application,
    26  		space configv3.Space,
    27  		organization configv3.Organization,
    28  		packageGUID string,
    29  		strategy constant.DeploymentStrategy,
    30  		noWait bool,
    31  		appAction constant.ApplicationAction,
    32  	) error
    33  
    34  	StageApp(
    35  		app resources.Application,
    36  		packageGUID string,
    37  		space configv3.Space,
    38  	) (resources.Droplet, error)
    39  
    40  	StartApp(
    41  		app resources.Application,
    42  		droplet resources.Droplet,
    43  		strategy constant.DeploymentStrategy,
    44  		noWait bool,
    45  		space configv3.Space,
    46  		organization configv3.Organization,
    47  		appAction constant.ApplicationAction,
    48  	) error
    49  }
    50  
    51  type Stager struct {
    52  	Actor    stagingAndStartActor
    53  	UI       command.UI
    54  	Config   command.Config
    55  	LogCache sharedaction.LogCacheClient
    56  }
    57  
    58  type stagingAndStartActor interface {
    59  	CreateDeploymentByApplicationAndDroplet(appGUID string, dropletGUID string) (string, v7action.Warnings, error)
    60  	GetDetailedAppSummary(appName string, spaceGUID string, withObfuscatedValues bool) (v7action.DetailedApplicationSummary, v7action.Warnings, error)
    61  	GetStreamingLogsForApplicationByNameAndSpace(appName string, spaceGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc, v7action.Warnings, error)
    62  	PollStart(app resources.Application, noWait bool, handleProcessStats func(string)) (v7action.Warnings, error)
    63  	PollStartForRolling(app resources.Application, deploymentGUID string, noWait bool, handleProcessStats func(string)) (v7action.Warnings, error)
    64  	SetApplicationDroplet(appGUID string, dropletGUID string) (v7action.Warnings, error)
    65  	StagePackage(packageGUID, appName, spaceGUID string) (<-chan resources.Droplet, <-chan v7action.Warnings, <-chan error)
    66  	StartApplication(appGUID string) (v7action.Warnings, error)
    67  	StopApplication(appGUID string) (v7action.Warnings, error)
    68  }
    69  
    70  func NewAppStager(actor stagingAndStartActor, ui command.UI, config command.Config, logCache sharedaction.LogCacheClient) AppStager {
    71  	return &Stager{
    72  		Actor:    actor,
    73  		UI:       ui,
    74  		Config:   config,
    75  		LogCache: logCache,
    76  	}
    77  }
    78  
    79  func (stager *Stager) StageAndStart(
    80  	app resources.Application,
    81  	space configv3.Space,
    82  	organization configv3.Organization,
    83  	packageGUID string,
    84  	strategy constant.DeploymentStrategy,
    85  	noWait bool,
    86  	appAction constant.ApplicationAction,
    87  ) error {
    88  
    89  	droplet, err := stager.StageApp(app, packageGUID, space)
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	stager.UI.DisplayNewline()
    95  
    96  	err = stager.StartApp(app, droplet, strategy, noWait, space, organization, appAction)
    97  	if err != nil {
    98  		return err
    99  	}
   100  
   101  	return nil
   102  }
   103  
   104  func (stager *Stager) StageApp(app resources.Application, packageGUID string, space configv3.Space) (resources.Droplet, error) {
   105  	logStream, logErrStream, stopLogStreamFunc, logWarnings, logErr := stager.Actor.GetStreamingLogsForApplicationByNameAndSpace(app.Name, space.GUID, stager.LogCache)
   106  	stager.UI.DisplayWarnings(logWarnings)
   107  	if logErr != nil {
   108  		return resources.Droplet{}, logErr
   109  	}
   110  	defer stopLogStreamFunc()
   111  
   112  	stager.UI.DisplayText("Staging app and tracing logs...")
   113  	dropletStream, warningsStream, errStream := stager.Actor.StagePackage(
   114  		packageGUID,
   115  		app.Name,
   116  		space.GUID,
   117  	)
   118  
   119  	droplet, err := PollStage(dropletStream, warningsStream, errStream, logStream, logErrStream, stager.UI)
   120  	if err != nil {
   121  		return resources.Droplet{}, err
   122  	}
   123  
   124  	return droplet, nil
   125  }
   126  
   127  func (stager *Stager) StartApp(
   128  	app resources.Application,
   129  	droplet resources.Droplet,
   130  	strategy constant.DeploymentStrategy,
   131  	noWait bool,
   132  	space configv3.Space,
   133  	organization configv3.Organization,
   134  	appAction constant.ApplicationAction,
   135  ) error {
   136  	if strategy == constant.DeploymentStrategyRolling {
   137  		stager.UI.DisplayText("Creating deployment for app {{.AppName}}...\n",
   138  			map[string]interface{}{
   139  				"AppName": app.Name,
   140  			},
   141  		)
   142  		deploymentGUID, warnings, err := stager.Actor.CreateDeploymentByApplicationAndDroplet(app.GUID, droplet.GUID)
   143  		stager.UI.DisplayWarnings(warnings)
   144  		if err != nil {
   145  			return err
   146  		}
   147  
   148  		stager.UI.DisplayText("Waiting for app to deploy...\n")
   149  
   150  		handleInstanceDetails := func(instanceDetails string) {
   151  			stager.UI.DisplayText(instanceDetails)
   152  		}
   153  
   154  		warnings, err = stager.Actor.PollStartForRolling(app, deploymentGUID, noWait, handleInstanceDetails)
   155  		stager.UI.DisplayNewline()
   156  		stager.UI.DisplayWarnings(warnings)
   157  		if err != nil {
   158  			return err
   159  		}
   160  	} else {
   161  		user, err := stager.Config.CurrentUser()
   162  		if err != nil {
   163  			return err
   164  		}
   165  
   166  		flavorText := fmt.Sprintf("%s app {{.App}} in org {{.Org}} / space {{.Space}} as {{.UserName}}...", appAction)
   167  		stager.UI.DisplayTextWithFlavor(flavorText,
   168  			map[string]interface{}{
   169  				"App":      app.Name,
   170  				"Org":      organization.Name,
   171  				"Space":    space.Name,
   172  				"UserName": user.Name,
   173  			},
   174  		)
   175  		stager.UI.DisplayNewline()
   176  
   177  		if app.Started() {
   178  			if appAction == constant.ApplicationStarting {
   179  				stager.UI.DisplayText("App '{{.AppName}}' is already started.",
   180  					map[string]interface{}{
   181  						"AppName": app.Name,
   182  					})
   183  				stager.UI.DisplayOK()
   184  				return nil
   185  
   186  			} else {
   187  				stager.UI.DisplayText("Stopping app...")
   188  				stager.UI.DisplayNewline()
   189  
   190  				warnings, err := stager.Actor.StopApplication(app.GUID)
   191  				stager.UI.DisplayWarnings(warnings)
   192  				if err != nil {
   193  					return err
   194  				}
   195  			}
   196  		}
   197  
   198  		if droplet.GUID != "" {
   199  			// attach droplet to app
   200  			warnings, err := stager.Actor.SetApplicationDroplet(app.GUID, droplet.GUID)
   201  			stager.UI.DisplayWarnings(warnings)
   202  			if err != nil {
   203  				return err
   204  			}
   205  		}
   206  
   207  		stager.UI.DisplayText("Waiting for app to start...")
   208  		stager.UI.DisplayNewline()
   209  
   210  		// start the application
   211  		warnings, err := stager.Actor.StartApplication(app.GUID)
   212  		stager.UI.DisplayWarnings(warnings)
   213  		if err != nil {
   214  			return err
   215  		}
   216  
   217  		handleInstanceDetails := func(instanceDetails string) {
   218  			stager.UI.DisplayText(instanceDetails)
   219  		}
   220  
   221  		warnings, err = stager.Actor.PollStart(app, noWait, handleInstanceDetails)
   222  		stager.UI.DisplayNewline()
   223  		stager.UI.DisplayWarnings(warnings)
   224  		if err != nil {
   225  			return err
   226  		}
   227  	}
   228  
   229  	summary, warnings, err := stager.Actor.GetDetailedAppSummary(
   230  		app.Name,
   231  		space.GUID,
   232  		false,
   233  	)
   234  	stager.UI.DisplayWarnings(warnings)
   235  	if err != nil {
   236  		return err
   237  	}
   238  
   239  	appSummaryDisplayer := NewAppSummaryDisplayer(stager.UI)
   240  	appSummaryDisplayer.AppDisplay(summary, false)
   241  
   242  	return nil
   243  }