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 }