github.com/liamawhite/cli-with-i18n@v6.32.1-0.20171122084555-dede0a5c3448+incompatible/command/v3/shared/app_summary_displayer.go (about)

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