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 }