github.com/nimakaviani/cli@v6.37.1-0.20180619223813-e734901a73fa+incompatible/command/v3/shared/app_summary_displayer.go (about)

     1  package shared
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  
     8  	"code.cloudfoundry.org/bytefmt"
     9  	"code.cloudfoundry.org/cli/actor/v2action"
    10  	"code.cloudfoundry.org/cli/actor/v3action"
    11  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
    12  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    13  	"code.cloudfoundry.org/cli/command"
    14  )
    15  
    16  type AppSummaryDisplayer struct {
    17  	UI              command.UI
    18  	Config          command.Config
    19  	Actor           V3AppSummaryActor
    20  	V2AppRouteActor V2AppRouteActor
    21  	AppName         string
    22  }
    23  
    24  //go:generate counterfeiter . V2AppRouteActor
    25  
    26  type V2AppRouteActor interface {
    27  	GetApplicationRoutes(appGUID string) (v2action.Routes, v2action.Warnings, error)
    28  }
    29  
    30  //go:generate counterfeiter . V3AppSummaryActor
    31  
    32  type V3AppSummaryActor interface {
    33  	GetApplicationSummaryByNameAndSpace(appName string, spaceGUID string) (v3action.ApplicationSummary, v3action.Warnings, error)
    34  }
    35  
    36  func (display AppSummaryDisplayer) DisplayAppInfo() error {
    37  	summary, warnings, err := display.Actor.GetApplicationSummaryByNameAndSpace(display.AppName, display.Config.TargetedSpace().GUID)
    38  	display.UI.DisplayWarnings(warnings)
    39  	if err != nil {
    40  		return err
    41  	}
    42  	summary.ProcessSummaries.Sort()
    43  
    44  	var routes v2action.Routes
    45  	if len(summary.ProcessSummaries) > 0 {
    46  		var routeWarnings v2action.Warnings
    47  		routes, routeWarnings, err = display.V2AppRouteActor.GetApplicationRoutes(summary.Application.GUID)
    48  		display.UI.DisplayWarnings(routeWarnings)
    49  		if _, ok := err.(ccerror.ResourceNotFoundError); err != nil && !ok {
    50  			return err
    51  		}
    52  	}
    53  
    54  	display.displayAppTable(summary, routes)
    55  
    56  	return nil
    57  }
    58  
    59  func (display AppSummaryDisplayer) displayAppInstancesTable(processSummary v3action.ProcessSummary) {
    60  	display.UI.DisplayNewline()
    61  
    62  	display.UI.DisplayTextWithBold("{{.ProcessType}}:{{.HealthyInstanceCount}}/{{.TotalInstanceCount}}", map[string]interface{}{
    63  		"ProcessType":          processSummary.Type,
    64  		"HealthyInstanceCount": processSummary.HealthyInstanceCount(),
    65  		"TotalInstanceCount":   processSummary.TotalInstanceCount(),
    66  	})
    67  
    68  	if !display.processHasAnInstance(&processSummary) {
    69  		return
    70  	}
    71  
    72  	table := [][]string{
    73  		{
    74  			"",
    75  			display.UI.TranslateText("state"),
    76  			display.UI.TranslateText("since"),
    77  			display.UI.TranslateText("cpu"),
    78  			display.UI.TranslateText("memory"),
    79  			display.UI.TranslateText("disk"),
    80  		},
    81  	}
    82  
    83  	for _, instance := range processSummary.InstanceDetails {
    84  		table = append(table, []string{
    85  			fmt.Sprintf("#%d", instance.Index),
    86  			display.UI.TranslateText(strings.ToLower(string(instance.State))),
    87  			display.appInstanceDate(instance.StartTime()),
    88  			fmt.Sprintf("%.1f%%", instance.CPU*100),
    89  			display.UI.TranslateText("{{.MemUsage}} of {{.MemQuota}}", map[string]interface{}{
    90  				"MemUsage": bytefmt.ByteSize(instance.MemoryUsage),
    91  				"MemQuota": bytefmt.ByteSize(instance.MemoryQuota),
    92  			}),
    93  			display.UI.TranslateText("{{.DiskUsage}} of {{.DiskQuota}}", map[string]interface{}{
    94  				"DiskUsage": bytefmt.ByteSize(instance.DiskUsage),
    95  				"DiskQuota": bytefmt.ByteSize(instance.DiskQuota),
    96  			}),
    97  		})
    98  	}
    99  
   100  	display.UI.DisplayInstancesTableForApp(table)
   101  }
   102  
   103  func (display AppSummaryDisplayer) DisplayAppProcessInfo() error {
   104  	summary, warnings, err := display.Actor.GetApplicationSummaryByNameAndSpace(display.AppName, display.Config.TargetedSpace().GUID)
   105  	display.UI.DisplayWarnings(warnings)
   106  	if err != nil {
   107  		return err
   108  	}
   109  	summary.ProcessSummaries.Sort()
   110  
   111  	display.displayProcessTable(summary)
   112  	return nil
   113  }
   114  
   115  func (display AppSummaryDisplayer) displayAppTable(summary v3action.ApplicationSummary, routes v2action.Routes) {
   116  	keyValueTable := [][]string{
   117  		{display.UI.TranslateText("name:"), summary.Application.Name},
   118  		{display.UI.TranslateText("requested state:"), strings.ToLower(string(summary.State))},
   119  		{display.UI.TranslateText("processes:"), summary.ProcessSummaries.String()},
   120  		{display.UI.TranslateText("memory usage:"), display.usageSummary(summary.ProcessSummaries)},
   121  		{display.UI.TranslateText("routes:"), routes.Summary()},
   122  		{display.UI.TranslateText("stack:"), summary.CurrentDroplet.Stack},
   123  	}
   124  
   125  	var lifecycleInfo []string
   126  
   127  	if summary.LifecycleType == constant.AppLifecycleTypeDocker {
   128  		lifecycleInfo = []string{display.UI.TranslateText("docker image:"), summary.CurrentDroplet.Image}
   129  	} else {
   130  		lifecycleInfo = []string{display.UI.TranslateText("buildpacks:"), display.buildpackNames(summary.CurrentDroplet.Buildpacks)}
   131  	}
   132  
   133  	keyValueTable = append(keyValueTable, lifecycleInfo)
   134  
   135  	crashedProcesses := []string{}
   136  	for i := range summary.ProcessSummaries {
   137  		if display.processInstancesAreAllCrashed(&summary.ProcessSummaries[i]) {
   138  			crashedProcesses = append(crashedProcesses, summary.ProcessSummaries[i].Type)
   139  		}
   140  	}
   141  
   142  	display.UI.DisplayKeyValueTableForV3App(keyValueTable, crashedProcesses)
   143  
   144  	display.displayProcessTable(summary)
   145  }
   146  
   147  func (display AppSummaryDisplayer) displayProcessTable(summary v3action.ApplicationSummary) {
   148  	appHasARunningInstance := false
   149  
   150  	for processIdx := range summary.ProcessSummaries {
   151  		if display.processHasAnInstance(&summary.ProcessSummaries[processIdx]) {
   152  			appHasARunningInstance = true
   153  			break
   154  		}
   155  	}
   156  
   157  	if !appHasARunningInstance {
   158  		display.UI.DisplayNewline()
   159  		display.UI.DisplayText("There are no running instances of this app.")
   160  		return
   161  	}
   162  
   163  	for _, process := range summary.ProcessSummaries {
   164  		display.displayAppInstancesTable(process)
   165  	}
   166  }
   167  
   168  func (AppSummaryDisplayer) usageSummary(processSummaries v3action.ProcessSummaries) string {
   169  	var usageStrings []string
   170  	for _, summary := range processSummaries {
   171  		if summary.TotalInstanceCount() > 0 {
   172  			usageStrings = append(usageStrings, fmt.Sprintf("%dM x %d", summary.MemoryInMB.Value, summary.TotalInstanceCount()))
   173  		}
   174  	}
   175  
   176  	return strings.Join(usageStrings, ", ")
   177  }
   178  
   179  func (AppSummaryDisplayer) buildpackNames(buildpacks []v3action.Buildpack) string {
   180  	var names []string
   181  	for _, buildpack := range buildpacks {
   182  		if buildpack.DetectOutput != "" {
   183  			names = append(names, buildpack.DetectOutput)
   184  		} else {
   185  			names = append(names, buildpack.Name)
   186  		}
   187  	}
   188  
   189  	return strings.Join(names, ", ")
   190  }
   191  
   192  func (AppSummaryDisplayer) appInstanceDate(input time.Time) string {
   193  	return input.Local().Format("2006-01-02 15:04:05 PM")
   194  }
   195  
   196  func (AppSummaryDisplayer) processHasAnInstance(processSummary *v3action.ProcessSummary) bool {
   197  	for instanceIdx := range processSummary.InstanceDetails {
   198  		if processSummary.InstanceDetails[instanceIdx].State != constant.ProcessInstanceDown {
   199  			return true
   200  		}
   201  	}
   202  
   203  	return false
   204  }
   205  
   206  func (AppSummaryDisplayer) processInstancesAreAllCrashed(processSummary *v3action.ProcessSummary) bool {
   207  	if len(processSummary.InstanceDetails) < 1 {
   208  		return false
   209  	}
   210  
   211  	for instanceIdx := range processSummary.InstanceDetails {
   212  		if processSummary.InstanceDetails[instanceIdx].State != constant.ProcessInstanceCrashed {
   213  			return false
   214  		}
   215  	}
   216  
   217  	return true
   218  }