mirror of https://github.com/dapr/cli.git
193 lines
5.2 KiB
Go
193 lines
5.2 KiB
Go
// ------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation and Dapr Contributors.
|
|
// Licensed under the MIT License.
|
|
// ------------------------------------------------------------
|
|
|
|
package standalone
|
|
|
|
import (
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/dapr/cli/pkg/age"
|
|
"github.com/dapr/cli/pkg/metadata"
|
|
"github.com/dapr/cli/utils"
|
|
ps "github.com/mitchellh/go-ps"
|
|
process "github.com/shirou/gopsutil/process"
|
|
)
|
|
|
|
// ListOutput represents the application ID, application port and creation time.
|
|
type ListOutput struct {
|
|
AppID string `csv:"APP ID" json:"appId" yaml:"appId"`
|
|
HTTPPort int `csv:"HTTP PORT" json:"httpPort" yaml:"httpPort"`
|
|
GRPCPort int `csv:"GRPC PORT" json:"grpcPort" yaml:"grpcPort"`
|
|
AppPort int `csv:"APP PORT" json:"appPort" yaml:"appPort"`
|
|
MetricsEnabled bool `csv:"-" json:"metricsEnabled" yaml:"metricsEnabled"` // Not displayed in table, consumed by dashboard.
|
|
Command string `csv:"COMMAND" json:"command" yaml:"command"`
|
|
Age string `csv:"AGE" json:"age" yaml:"age"`
|
|
Created string `csv:"CREATED" json:"created" yaml:"created"`
|
|
PID int `csv:"PID" json:"pid" yaml:"pid"`
|
|
}
|
|
|
|
// runData is a placeholder for collected information linking cli and sidecar.
|
|
type runData struct {
|
|
cliPID int
|
|
sidecarPID int
|
|
grpcPort int
|
|
httpPort int
|
|
appPort int
|
|
appID string
|
|
appCmd string
|
|
enableMetrics bool
|
|
maxRequestBodySize int
|
|
}
|
|
|
|
func (d *daprProcess) List() ([]ListOutput, error) {
|
|
return List()
|
|
}
|
|
|
|
// List outputs all the applications.
|
|
func List() ([]ListOutput, error) {
|
|
list := []ListOutput{}
|
|
|
|
processes, err := ps.Processes()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Links a cli PID to the corresponding sidecar Process.
|
|
cliToSidecarMap := make(map[int]*runData)
|
|
|
|
// Populates the map if all data is available for the sidecar.
|
|
for _, proc := range processes {
|
|
executable := strings.ToLower(proc.Executable())
|
|
if (executable == "daprd") || (executable == "daprd.exe") {
|
|
procDetails, err := process.NewProcess(int32(proc.Pid()))
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
cmdLine, err := procDetails.Cmdline()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
cmdLineItems := strings.Fields(cmdLine)
|
|
if len(cmdLineItems) <= 1 {
|
|
continue
|
|
}
|
|
|
|
argumentsMap := make(map[string]string)
|
|
for i := 1; i < len(cmdLineItems)-1; i += 2 {
|
|
argumentsMap[cmdLineItems[i]] = cmdLineItems[i+1]
|
|
}
|
|
|
|
httpPort, err := strconv.Atoi(argumentsMap["--dapr-http-port"])
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
grpcPort, err := strconv.Atoi(argumentsMap["--dapr-grpc-port"])
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
appPort, err := strconv.Atoi(argumentsMap["--app-port"])
|
|
if err != nil {
|
|
appPort = 0
|
|
}
|
|
|
|
enableMetrics, err := strconv.ParseBool(argumentsMap["--enable-metrics"])
|
|
if err != nil {
|
|
// Default is true for metrics.
|
|
enableMetrics = true
|
|
}
|
|
appID := argumentsMap["--app-id"]
|
|
appCmd := ""
|
|
cliPIDString := ""
|
|
socket := argumentsMap["--unix-domain-socket"]
|
|
appMetadata, err := metadata.Get(httpPort, appID, socket)
|
|
if err == nil {
|
|
appCmd = appMetadata.Extended["appCommand"]
|
|
cliPIDString = appMetadata.Extended["cliPID"]
|
|
}
|
|
|
|
// Parse functions return an error on bad input.
|
|
cliPID, err := strconv.Atoi(cliPIDString)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
maxRequestBodySize, err := strconv.Atoi(argumentsMap["--dapr-http-max-request-size"])
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
run := runData{
|
|
cliPID: cliPID,
|
|
sidecarPID: proc.Pid(),
|
|
grpcPort: grpcPort,
|
|
httpPort: httpPort,
|
|
appPort: appPort,
|
|
appID: appID,
|
|
appCmd: appCmd,
|
|
enableMetrics: enableMetrics,
|
|
maxRequestBodySize: maxRequestBodySize,
|
|
}
|
|
|
|
cliToSidecarMap[cliPID] = &run
|
|
}
|
|
}
|
|
|
|
myPID := os.Getpid()
|
|
// The master list comes from cli processes, even if sidecar is not up.
|
|
for _, proc := range processes {
|
|
executable := strings.ToLower(proc.Executable())
|
|
if (executable == "dapr") || (executable == "dapr.exe") {
|
|
pID := proc.Pid()
|
|
if pID == myPID {
|
|
// Do not display current `dapr list` process.
|
|
continue
|
|
}
|
|
|
|
procDetails, err := process.NewProcess(int32(pID))
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
createUnixTimeMilliseconds, err := procDetails.CreateTime()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
createTime := time.Unix(createUnixTimeMilliseconds/1000, 0)
|
|
|
|
listRow := ListOutput{
|
|
Created: createTime.Format("2006-01-02 15:04.05"),
|
|
Age: age.GetAge(createTime),
|
|
PID: proc.Pid(),
|
|
}
|
|
|
|
// Now we use sidecar into to decorate with more info (empty, if sidecar is down).
|
|
run, ok := cliToSidecarMap[proc.Pid()]
|
|
if ok {
|
|
listRow.AppID = run.appID
|
|
listRow.HTTPPort = run.httpPort
|
|
listRow.GRPCPort = run.grpcPort
|
|
listRow.AppPort = run.appPort
|
|
listRow.MetricsEnabled = run.enableMetrics
|
|
listRow.Command = utils.TruncateString(run.appCmd, 20)
|
|
}
|
|
|
|
// filter only dashboard instance
|
|
if listRow.AppID != "" {
|
|
list = append(list, listRow)
|
|
}
|
|
}
|
|
}
|
|
|
|
return list, nil
|
|
}
|