diff --git a/client/client.go b/client/client.go index 00cb8c06..f468bda2 100644 --- a/client/client.go +++ b/client/client.go @@ -26,10 +26,8 @@ import ( "time" docker "github.com/fsouza/go-dockerclient" - "github.com/sirupsen/logrus" vppagent "go.ligato.io/vpp-agent/v3/cmd/agentctl/client" "go.ligato.io/vpp-agent/v3/cmd/agentctl/client/tlsconfig" - linux_nsplugin "go.ligato.io/vpp-agent/v3/plugins/linux/nsplugin" "go.pantheon.tech/stonework/plugins/cnfreg" ) @@ -37,7 +35,6 @@ import ( const ( DefaultHost = "127.0.0.1" DefaultHTTPClientTimeout = 60 * time.Second - DefaultPortGRPC = 9991 DefaultPortHTTP = 9191 DockerComposeServiceLabel = "com.docker.compose.service" ) @@ -75,7 +72,6 @@ type API interface { // Client implements API interface. type Client struct { - nsPlugin *linux_nsplugin.NsPlugin dockerClient *docker.Client httpClient *http.Client host string @@ -101,7 +97,9 @@ func NewClient(opts ...Option) (*Client, error) { return nil, err } for _, o := range opts { - o(c) + if err = o(c); err != nil { + return nil, err + } } return c, nil @@ -172,9 +170,7 @@ func (c *Client) GetComponents() ([]Component, error) { return nil, err } containers = append(containers, c) - logrus.Warnf("[WLL] container name: %s, PID: %d, ENV: %+v", c.Name, c.State.Pid, c.Config.Env) } - logrus.Warnf("[WLL] number of containers: &d", len(containers)) cnfInfos := make(map[string]cnfreg.Info) for _, info := range infos { @@ -201,7 +197,7 @@ func (c *Client) GetComponents() ([]Component, error) { compo := &component{ agentclient: client, Name: info.MsLabel, - Mode: cnfModeToCompoMode(info.Mode), + Mode: cnfModeToCompoMode(info.CnfMode), Info: &info, } components = append(components, compo) diff --git a/client/component.go b/client/component.go index 7cc24816..b902c823 100644 --- a/client/component.go +++ b/client/component.go @@ -4,7 +4,6 @@ import ( "context" "fmt" - "go.ligato.io/cn-infra/v2/health/probe" "go.ligato.io/vpp-agent/v3/cmd/agentctl/api/types" "go.ligato.io/vpp-agent/v3/cmd/agentctl/client" @@ -19,17 +18,16 @@ const ( // Foreign means the component is not managed by StoneWork ComponentForeign ComponentMode = iota - // Stonework means the component is a StoneWork instance - ComponentStonework - // StoneworkModule means the component is a StoneWork module managed by StoneWork ComponentStoneworkModule + + // Stonework means the component is a StoneWork instance + ComponentStonework ) // Component is a component of StoneWork. It can be StoneWork instance itself, // a CNF connected to it or other Ligato service in connected to StoneWork. type Component interface { - // Client() *client.Client GetName() string GetMode() ComponentMode GetInfo() *cnfreg.Info @@ -79,20 +77,6 @@ func (c *component) SchedulerValues() ([]*kvscheduler.BaseValueStatus, error) { return values, nil } -func (c *component) Readiness() (*probe.ExposedStatus, error) { - if c.Mode == ComponentForeign { - return nil, fmt.Errorf("cannot get readiness of component %s, this component in not managed by StoneWork", c.Name) - } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - status, err := c.agentclient.Status(ctx) - if err != nil { - return nil, err - } - return status, nil -} - func cnfModeToCompoMode(cm cnfregpb.CnfMode) ComponentMode { switch cm { case cnfregpb.CnfMode_STANDALONE: diff --git a/cmd/swctl/cli.go b/cmd/swctl/cli.go index 45d4b1d4..13d466f9 100644 --- a/cmd/swctl/cli.go +++ b/cmd/swctl/cli.go @@ -10,8 +10,6 @@ import ( "github.com/moby/term" "github.com/sirupsen/logrus" - // agentcli "go.ligato.io/vpp-agent/v3/cmd/agentctl/cli" - "go.pantheon.tech/stonework/client" ) diff --git a/cmd/swctl/cmd_status.go b/cmd/swctl/cmd_status.go index 991b05db..5075507f 100644 --- a/cmd/swctl/cmd_status.go +++ b/cmd/swctl/cmd_status.go @@ -3,6 +3,7 @@ package main import ( "fmt" "io" + "os/exec" "strconv" "strings" "sync" @@ -10,7 +11,7 @@ import ( "github.com/gookit/color" "github.com/olekukonko/tablewriter" "github.com/spf13/cobra" - "golang.org/x/exp/constraints" + "github.com/spf13/pflag" "golang.org/x/exp/slices" "go.ligato.io/vpp-agent/v3/proto/ligato/kvscheduler" @@ -27,15 +28,23 @@ import ( const statusExample = ` # Show status for all components $ swctl status + + # Show interface status of StoneWork VPP instance + $ swctl status --show-interfaces ` -type StatusCmdOptions struct { - Args []string - Format string +type StatusOptions struct { + Format string + ShowInterfaces bool +} + +func (opts *StatusOptions) InstallFlags(flagset *pflag.FlagSet) { + flagset.StringVar(&opts.Format, "format", "", "Format for the output (yaml, json, go template)") + flagset.BoolVar(&opts.ShowInterfaces, "show-interfaces", false, "Show interface status of StoneWork VPP instance") } func NewStatusCmd(cli Cli) *cobra.Command { - var opts StatusCmdOptions + var opts StatusOptions cmd := &cobra.Command{ Use: "status [flags]", Short: "Show status of StoneWork components", @@ -45,10 +54,10 @@ func NewStatusCmd(cli Cli) *cobra.Command { UnknownFlags: true, }, RunE: func(cmd *cobra.Command, args []string) error { - opts.Args = args return runStatusCmd(cli, opts) }, } + opts.InstallFlags(cmd.PersistentFlags()) return cmd } @@ -57,7 +66,20 @@ type statusInfo struct { ConfigCounts configCounts } -func runStatusCmd(cli Cli, opts StatusCmdOptions) error { +func runStatusCmd(cli Cli, opts StatusOptions) error { + if opts.ShowInterfaces { + cmd := fmt.Sprintf("vpp-probe --env=%s --query label=%s=stonework discover", defaultVppProbeEnv, client.DockerComposeServiceLabel) + formatArg := fmt.Sprintf("--format=%s", opts.Format) + out, err := cli.Exec(cmd, []string{formatArg}) + if err != nil { + if ee, ok := err.(*exec.ExitError); ok { + return fmt.Errorf("%v: %s", ee.String(), ee.Stderr) + } + } + fmt.Fprintln(cli.Out(), out) + return nil + } + resp, err := cli.Client().GetComponents() if err != nil { return err @@ -71,11 +93,6 @@ func runStatusCmd(cli Cli, opts StatusCmdOptions) error { var wg sync.WaitGroup infoCh := make(chan infoWithErr) - type fetched struct { - values []*kvscheduler.BaseValueStatus - err error - } - for _, compo := range resp { wg.Add(1) go func(compo client.Component) { @@ -108,11 +125,14 @@ func runStatusCmd(cli Cli, opts StatusCmdOptions) error { } infos = append(infos, i.statusInfo) } - slices.SortFunc(infos, cmpInfos) - // if err := formatAsTemplate(cli.Out(), "json", resp); err != nil { - // return err - // } - printStatusTable(cli.Out(), infos) + slices.SortFunc(infos, cmpStatus) + if opts.Format == "" { + printStatusTable(cli.Out(), infos) + } else { + if err := formatAsTemplate(cli.Out(), opts.Format, infos); err != nil { + return err + } + } return nil } @@ -143,24 +163,12 @@ func countConfig(baseVals []*kvscheduler.BaseValueStatus) configCounts { return res } -type comparable interface { - constraints.Integer | ~string -} - -func less[T comparable](a, b T) bool { - if a > b { - return true +func cmpStatus(a, b statusInfo) bool { + greater := a.GetMode() > b.GetMode() + if !greater && a.GetMode() == b.GetMode() { + greater = a.GetName() > b.GetName() } - return false -} - -func cmpInfos(a, b statusInfo) bool { - res := less(a.GetMode(), b.GetMode()) - bLessA := less(b.GetMode(), a.GetMode()) - if !(res || bLessA) { - res = less(a.GetName(), b.GetName()) - } - return res + return greater } func printStatusTable(out io.Writer, infos []statusInfo) { @@ -193,8 +201,8 @@ func printStatusTable(out io.Writer, infos []statusInfo) { table.Rich(row, clrs) continue } - config := info.ConfigCounts.String() - configColor := info.ConfigCounts.Color() + config := info.ConfigCounts.string() + configColor := info.ConfigCounts.color() compoInfo := info.GetInfo() grpcState := compoInfo.GRPCConnState.String() var statusClr int @@ -238,7 +246,7 @@ type configCounts struct { Unimplemented int } -func (c configCounts) String() string { +func (c configCounts) string() string { var fields []string if c.Ok != 0 { fields = append(fields, fmt.Sprintf("%d OK", c.Ok)) @@ -265,7 +273,7 @@ func (c configCounts) String() string { return strings.Join(fields, ", ") } -func (c configCounts) Color() int { +func (c configCounts) color() int { if c.Err > 0 { return tablewriter.FgHiRedColor } diff --git a/docs/SWCTL.md b/docs/SWCTL.md index 28507e02..90346711 100644 --- a/docs/SWCTL.md +++ b/docs/SWCTL.md @@ -228,14 +228,14 @@ swctl config history #### Status -To display the status of StoneWork components and their interfaces, run: +To display the status of StoneWork components, run: ```bash swctl status ``` > **Note** -> The `status` command is a simple wrapper for `vpp-probe discover`. +> When used with `--show-interfaces` flag the `status` command calls `vpp-probe discover`. #### Trace diff --git a/plugins/cnfreg/rest.go b/plugins/cnfreg/rest.go index e6729340..b25e42d8 100644 --- a/plugins/cnfreg/rest.go +++ b/plugins/cnfreg/rest.go @@ -30,7 +30,7 @@ import ( type Info struct { PID int MsLabel string - Mode pb.CnfMode + CnfMode pb.CnfMode IPAddr string GRPCPort int HTTPPort int @@ -54,7 +54,7 @@ func (p *Plugin) statusHandler(formatter *render.Render) http.HandlerFunc { swInfo := &Info{ PID: os.Getpid(), MsLabel: p.ServiceLabel.GetAgentLabel(), - Mode: pb.CnfMode_STONEWORK, + CnfMode: pb.CnfMode_STONEWORK, IPAddr: p.ipAddress.String(), GRPCPort: p.GRPCPlugin.GetPort(), HTTPPort: p.HTTPPlugin.GetPort(), @@ -66,7 +66,7 @@ func (p *Plugin) statusHandler(formatter *render.Render) http.HandlerFunc { swModInfo := &Info{ PID: swMod.pid, MsLabel: swMod.cnfMsLabel, - Mode: pb.CnfMode_STONEWORK_MODULE, + CnfMode: pb.CnfMode_STONEWORK_MODULE, IPAddr: swMod.ipAddress, GRPCPort: swMod.grpcPort, HTTPPort: swMod.httpPort,