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 }