github.com/swisscom/cloudfoundry-cli@v7.1.0+incompatible/cf/commands/application/app.go (about)

     1  package application
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"code.cloudfoundry.org/cli/cf/flags"
     8  	. "code.cloudfoundry.org/cli/cf/i18n"
     9  	"code.cloudfoundry.org/cli/plugin/models"
    10  
    11  	"code.cloudfoundry.org/cli/cf/api"
    12  	"code.cloudfoundry.org/cli/cf/api/appinstances"
    13  	"code.cloudfoundry.org/cli/cf/api/stacks"
    14  	"code.cloudfoundry.org/cli/cf/commandregistry"
    15  	"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
    16  	"code.cloudfoundry.org/cli/cf/errors"
    17  	"code.cloudfoundry.org/cli/cf/formatters"
    18  	"code.cloudfoundry.org/cli/cf/models"
    19  	"code.cloudfoundry.org/cli/cf/requirements"
    20  	"code.cloudfoundry.org/cli/cf/terminal"
    21  	"code.cloudfoundry.org/cli/cf/uihelpers"
    22  )
    23  
    24  //go:generate counterfeiter . Displayer
    25  
    26  type Displayer interface {
    27  	ShowApp(app models.Application, orgName string, spaceName string) error
    28  }
    29  
    30  type ShowApp struct {
    31  	ui               terminal.UI
    32  	config           coreconfig.Reader
    33  	appSummaryRepo   api.AppSummaryRepository
    34  	appInstancesRepo appinstances.Repository
    35  	stackRepo        stacks.StackRepository
    36  	appReq           requirements.ApplicationRequirement
    37  	pluginAppModel   *plugin_models.GetAppModel
    38  	pluginCall       bool
    39  }
    40  
    41  func init() {
    42  	commandregistry.Register(&ShowApp{})
    43  }
    44  
    45  func (cmd *ShowApp) MetaData() commandregistry.CommandMetadata {
    46  	fs := make(map[string]flags.FlagSet)
    47  	fs["guid"] = &flags.BoolFlag{Name: "guid", Usage: T("Retrieve and display the given app's guid.  All other health and status output for the app is suppressed.")}
    48  
    49  	return commandregistry.CommandMetadata{
    50  		Name:        "app",
    51  		Description: T("Display health and status for an app"),
    52  		Usage: []string{
    53  			T("CF_NAME app APP_NAME"),
    54  		},
    55  		Flags: fs,
    56  	}
    57  }
    58  
    59  func (cmd *ShowApp) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) ([]requirements.Requirement, error) {
    60  	if len(fc.Args()) != 1 {
    61  		cmd.ui.Failed(T("Incorrect Usage. Requires an argument\n\n") + commandregistry.Commands.CommandUsage("app"))
    62  		return nil, fmt.Errorf("Incorrect usage: %d arguments of %d required", len(fc.Args()), 1)
    63  	}
    64  
    65  	cmd.appReq = requirementsFactory.NewApplicationRequirement(fc.Args()[0])
    66  
    67  	reqs := []requirements.Requirement{
    68  		requirementsFactory.NewLoginRequirement(),
    69  		requirementsFactory.NewTargetedSpaceRequirement(),
    70  		cmd.appReq,
    71  	}
    72  
    73  	return reqs, nil
    74  }
    75  
    76  func (cmd *ShowApp) SetDependency(deps commandregistry.Dependency, pluginCall bool) commandregistry.Command {
    77  	cmd.ui = deps.UI
    78  	cmd.config = deps.Config
    79  	cmd.appSummaryRepo = deps.RepoLocator.GetAppSummaryRepository()
    80  	cmd.appInstancesRepo = deps.RepoLocator.GetAppInstancesRepository()
    81  	cmd.stackRepo = deps.RepoLocator.GetStackRepository()
    82  
    83  	cmd.pluginAppModel = deps.PluginModels.Application
    84  	cmd.pluginCall = pluginCall
    85  
    86  	return cmd
    87  }
    88  
    89  func (cmd *ShowApp) Execute(c flags.FlagContext) error {
    90  	app := cmd.appReq.GetApplication()
    91  
    92  	if c.Bool("guid") {
    93  		cmd.ui.Say(app.GUID)
    94  	} else {
    95  		err := cmd.ShowApp(app, cmd.config.OrganizationFields().Name, cmd.config.SpaceFields().Name)
    96  		if err != nil {
    97  			return err
    98  		}
    99  	}
   100  	return nil
   101  }
   102  
   103  func (cmd *ShowApp) ShowApp(app models.Application, orgName, spaceName string) error {
   104  	cmd.ui.Say(T("Showing health and status for app {{.AppName}} in org {{.OrgName}} / space {{.SpaceName}} as {{.Username}}...",
   105  		map[string]interface{}{
   106  			"AppName":   terminal.EntityNameColor(app.Name),
   107  			"OrgName":   terminal.EntityNameColor(orgName),
   108  			"SpaceName": terminal.EntityNameColor(spaceName),
   109  			"Username":  terminal.EntityNameColor(cmd.config.Username())}))
   110  
   111  	application, err := cmd.appSummaryRepo.GetSummary(app.GUID)
   112  
   113  	appIsStopped := (application.State == "stopped")
   114  	if assertionErr, ok := err.(errors.HTTPError); ok {
   115  		if assertionErr.ErrorCode() == errors.InstancesError || assertionErr.ErrorCode() == errors.NotStaged {
   116  			appIsStopped = true
   117  		}
   118  	}
   119  
   120  	if err != nil && !appIsStopped {
   121  		return err
   122  	}
   123  
   124  	var instances []models.AppInstanceFields
   125  	instances, err = cmd.appInstancesRepo.GetInstances(app.GUID)
   126  	if err != nil && !appIsStopped {
   127  		return err
   128  	}
   129  
   130  	if cmd.pluginCall {
   131  		cmd.populatePluginModel(application, app.Stack, instances)
   132  	}
   133  
   134  	cmd.ui.Ok()
   135  	cmd.ui.Say("\n%s %s", terminal.HeaderColor(T("requested state:")), uihelpers.ColoredAppState(application.ApplicationFields))
   136  	cmd.ui.Say("%s %s", terminal.HeaderColor(T("instances:")), uihelpers.ColoredAppInstances(application.ApplicationFields))
   137  
   138  	cmd.ui.Say(T("{{.Usage}} {{.FormattedMemory}} x {{.InstanceCount}} instances",
   139  		map[string]interface{}{
   140  			"Usage":           terminal.HeaderColor(T("usage:")),
   141  			"FormattedMemory": formatters.ByteSize(application.Memory * formatters.MEGABYTE),
   142  			"InstanceCount":   application.InstanceCount}))
   143  
   144  	var urls []string
   145  	for _, route := range application.Routes {
   146  		urls = append(urls, route.URL())
   147  	}
   148  
   149  	cmd.ui.Say("%s %s", terminal.HeaderColor(T("urls:")), strings.Join(urls, ", "))
   150  	var lastUpdated string
   151  	if application.PackageUpdatedAt != nil {
   152  		lastUpdated = application.PackageUpdatedAt.Format("Mon Jan 2 15:04:05 MST 2006")
   153  	} else {
   154  		lastUpdated = "unknown"
   155  	}
   156  	cmd.ui.Say("%s %s", terminal.HeaderColor(T("last uploaded:")), lastUpdated)
   157  
   158  	appStack, err := cmd.stackRepo.FindByGUID(application.ApplicationFields.StackGUID)
   159  	if appStack.Name != "" && err == nil {
   160  		cmd.ui.Say("%s %s", terminal.HeaderColor(T("stack:")), appStack.Name)
   161  	} else {
   162  		cmd.ui.Say("%s %s", terminal.HeaderColor(T("stack:")), "unknown")
   163  	}
   164  
   165  	if app.Buildpack != "" {
   166  		cmd.ui.Say("%s %s\n", terminal.HeaderColor(T("buildpack:")), app.Buildpack)
   167  	} else if app.DetectedBuildpack != "" {
   168  		cmd.ui.Say("%s %s\n", terminal.HeaderColor(T("buildpack:")), app.DetectedBuildpack)
   169  	} else {
   170  		cmd.ui.Say("%s %s\n", terminal.HeaderColor(T("buildpack:")), "unknown")
   171  	}
   172  
   173  	if appIsStopped {
   174  		cmd.ui.Say(T("There are no running instances of this app."))
   175  		return nil
   176  	}
   177  
   178  	table := cmd.ui.Table([]string{"", T("state"), T("since"), T("cpu"), T("memory"), T("disk"), T("details")})
   179  
   180  	for index, instance := range instances {
   181  		table.Add(
   182  			fmt.Sprintf("#%d", index),
   183  			uihelpers.ColoredInstanceState(instance),
   184  			instance.Since.Format("2006-01-02 03:04:05 PM"),
   185  			fmt.Sprintf("%.1f%%", instance.CPUUsage*100),
   186  			fmt.Sprintf(T("{{.MemUsage}} of {{.MemQuota}}",
   187  				map[string]interface{}{
   188  					"MemUsage": formatters.ByteSize(instance.MemUsage),
   189  					"MemQuota": formatters.ByteSize(instance.MemQuota)})),
   190  			fmt.Sprintf(T("{{.DiskUsage}} of {{.DiskQuota}}",
   191  				map[string]interface{}{
   192  					"DiskUsage": formatters.ByteSize(instance.DiskUsage),
   193  					"DiskQuota": formatters.ByteSize(instance.DiskQuota)})),
   194  			fmt.Sprintf("%s", instance.Details),
   195  		)
   196  	}
   197  
   198  	err = table.Print()
   199  	if err != nil {
   200  		return err
   201  	}
   202  	if err != nil {
   203  		return err
   204  	}
   205  	return nil
   206  }
   207  
   208  func (cmd *ShowApp) populatePluginModel(
   209  	getSummaryApp models.Application,
   210  	stack *models.Stack,
   211  	instances []models.AppInstanceFields,
   212  ) {
   213  	cmd.pluginAppModel.BuildpackUrl = getSummaryApp.BuildpackURL
   214  	cmd.pluginAppModel.Command = getSummaryApp.Command
   215  	cmd.pluginAppModel.DetectedStartCommand = getSummaryApp.DetectedStartCommand
   216  	cmd.pluginAppModel.DiskQuota = getSummaryApp.DiskQuota
   217  	cmd.pluginAppModel.EnvironmentVars = getSummaryApp.EnvironmentVars
   218  	cmd.pluginAppModel.Guid = getSummaryApp.GUID
   219  	cmd.pluginAppModel.HealthCheckTimeout = getSummaryApp.HealthCheckTimeout
   220  	cmd.pluginAppModel.InstanceCount = getSummaryApp.InstanceCount
   221  	cmd.pluginAppModel.Memory = getSummaryApp.Memory
   222  	cmd.pluginAppModel.Name = getSummaryApp.Name
   223  	cmd.pluginAppModel.PackageState = getSummaryApp.PackageState
   224  	cmd.pluginAppModel.PackageUpdatedAt = getSummaryApp.PackageUpdatedAt
   225  	cmd.pluginAppModel.RunningInstances = getSummaryApp.RunningInstances
   226  	cmd.pluginAppModel.SpaceGuid = getSummaryApp.SpaceGUID
   227  	cmd.pluginAppModel.Stack = &plugin_models.GetApp_Stack{
   228  		Name: stack.Name,
   229  		Guid: stack.GUID,
   230  	}
   231  	cmd.pluginAppModel.StagingFailedReason = getSummaryApp.StagingFailedReason
   232  	cmd.pluginAppModel.State = getSummaryApp.State
   233  
   234  	for _, instance := range instances {
   235  		instanceFields := plugin_models.GetApp_AppInstanceFields{
   236  			State:     string(instance.State),
   237  			Details:   instance.Details,
   238  			Since:     instance.Since,
   239  			CpuUsage:  instance.CPUUsage,
   240  			DiskQuota: instance.DiskQuota,
   241  			DiskUsage: instance.DiskUsage,
   242  			MemQuota:  instance.MemQuota,
   243  			MemUsage:  instance.MemUsage,
   244  		}
   245  		cmd.pluginAppModel.Instances = append(cmd.pluginAppModel.Instances, instanceFields)
   246  	}
   247  	if cmd.pluginAppModel.Instances == nil {
   248  		cmd.pluginAppModel.Instances = []plugin_models.GetApp_AppInstanceFields{}
   249  	}
   250  
   251  	for i := range getSummaryApp.Routes {
   252  		routeSummary := plugin_models.GetApp_RouteSummary{
   253  			Host: getSummaryApp.Routes[i].Host,
   254  			Guid: getSummaryApp.Routes[i].GUID,
   255  			Domain: plugin_models.GetApp_DomainFields{
   256  				Name: getSummaryApp.Routes[i].Domain.Name,
   257  				Guid: getSummaryApp.Routes[i].Domain.GUID,
   258  			},
   259  			Path: getSummaryApp.Routes[i].Path,
   260  			Port: getSummaryApp.Routes[i].Port,
   261  		}
   262  		cmd.pluginAppModel.Routes = append(cmd.pluginAppModel.Routes, routeSummary)
   263  	}
   264  	if cmd.pluginAppModel.Routes == nil {
   265  		cmd.pluginAppModel.Routes = []plugin_models.GetApp_RouteSummary{}
   266  	}
   267  
   268  	for i := range getSummaryApp.Services {
   269  		serviceSummary := plugin_models.GetApp_ServiceSummary{
   270  			Name: getSummaryApp.Services[i].Name,
   271  			Guid: getSummaryApp.Services[i].GUID,
   272  		}
   273  		cmd.pluginAppModel.Services = append(cmd.pluginAppModel.Services, serviceSummary)
   274  	}
   275  	if cmd.pluginAppModel.Services == nil {
   276  		cmd.pluginAppModel.Services = []plugin_models.GetApp_ServiceSummary{}
   277  	}
   278  }