Skip to content

Commit b302df8

Browse files
authored
Merge pull request #86 from StackVista/stac-21470
STAC-21470: Add agent list command
2 parents 9013c47 + 5370190 commit b302df8

File tree

76 files changed

+10491
-1747
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+10491
-1747
lines changed

cmd/agent.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package cmd
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
"github.com/stackvista/stackstate-cli/cmd/agent"
6+
"github.com/stackvista/stackstate-cli/internal/di"
7+
)
8+
9+
func AgentCommand(deps *di.Deps) *cobra.Command {
10+
cmd := &cobra.Command{
11+
Use: "agent",
12+
Short: "Manage the StackState agents",
13+
Long: "Manage the StackState agents.",
14+
}
15+
16+
cmd.AddCommand(agent.ListCommand(deps))
17+
return cmd
18+
}

cmd/agent/agent_list.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package agent
2+
3+
import (
4+
"cmp"
5+
"fmt"
6+
"slices"
7+
"time"
8+
9+
"github.com/spf13/cobra"
10+
"github.com/stackvista/stackstate-cli/generated/stackstate_api"
11+
"github.com/stackvista/stackstate-cli/internal/common"
12+
"github.com/stackvista/stackstate-cli/internal/di"
13+
"github.com/stackvista/stackstate-cli/internal/printer"
14+
)
15+
16+
func ListCommand(deps *di.Deps) *cobra.Command {
17+
cmd := &cobra.Command{
18+
Use: "list",
19+
Short: "List all registered agents",
20+
Long: "List all registered agents.",
21+
RunE: deps.CmdRunEWithApi(RunListCommand),
22+
}
23+
24+
return cmd
25+
}
26+
27+
const toMB = 1024 * 1024
28+
29+
func RunListCommand(cmd *cobra.Command, cli *di.Deps, api *stackstate_api.APIClient, serverInfo *stackstate_api.ServerInfo) common.CLIError {
30+
agents, resp, err := api.AgentRegistrationsApi.AllAgentRegistrations(cli.Context).Execute()
31+
32+
if err != nil {
33+
return common.NewResponseError(err, resp)
34+
}
35+
36+
agentList := agents.Agents
37+
38+
slices.SortFunc(agentList, func(a, b stackstate_api.AgentRegistration) int {
39+
if n := cmp.Compare(a.Lease, b.Lease); n != 0 {
40+
return n
41+
}
42+
// If leases are equal, order by registration moment
43+
return cmp.Compare(a.RegisteredEpochMs, b.RegisteredEpochMs)
44+
})
45+
46+
var active = 0
47+
var limited = 0
48+
var stale = 0
49+
50+
for _, agent := range agentList {
51+
switch agent.Lease {
52+
case stackstate_api.AGENTLEASE_ACTIVE:
53+
active++
54+
case stackstate_api.AGENTLEASE_LIMITED:
55+
limited++
56+
case stackstate_api.AGENTLEASE_STALE:
57+
stale++
58+
default:
59+
}
60+
}
61+
62+
if cli.IsJson() {
63+
cli.Printer.PrintJson(map[string]interface{}{
64+
"agents": agentList,
65+
})
66+
} else {
67+
data := make([][]interface{}, len(agentList))
68+
69+
for i, agent := range agentList {
70+
var info = agent.AgentData
71+
if info == nil {
72+
info = &stackstate_api.AgentData{Platform: "", CoreCount: 0, MemoryBytes: 0, KernelVersion: ""}
73+
}
74+
75+
data[i] = []interface{}{
76+
agent.AgentId,
77+
agent.Lease,
78+
time.UnixMilli(agent.RegisteredEpochMs).Format("2006-01-02 15:04:05 MST"),
79+
time.UnixMilli(agent.LeaseUntilEpochMs).Format("2006-01-02 15:04:05 MST"),
80+
fmt.Sprintf("%v", info.CoreCount),
81+
fmt.Sprintf("%vMB", info.MemoryBytes/toMB),
82+
info.Platform,
83+
info.KernelVersion,
84+
}
85+
}
86+
cli.Printer.Table(printer.TableData{
87+
Header: []string{"Host", "Lease", "Registered", "Last Lease", "CPUS", "Memory", "Platform", "Kernel"},
88+
Data: data,
89+
})
90+
91+
cli.Printer.PrintLn("")
92+
cli.Printer.PrintLn(fmt.Sprintf("Totals: %d active, %d limited, %d stale", active, limited, stale))
93+
}
94+
95+
return nil
96+
}

cmd/agent/agent_list_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package agent
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/stackvista/stackstate-cli/generated/stackstate_api"
8+
"github.com/stackvista/stackstate-cli/internal/di"
9+
"github.com/stackvista/stackstate-cli/internal/printer"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
var (
14+
SomeAgentRegistrations = []stackstate_api.AgentRegistration{
15+
{
16+
AgentId: "id1",
17+
Lease: stackstate_api.AGENTLEASE_ACTIVE,
18+
LeaseUntilEpochMs: 0,
19+
RegisteredEpochMs: 0,
20+
AgentData: &stackstate_api.AgentData{
21+
Platform: "platform",
22+
CoreCount: 4,
23+
MemoryBytes: 16 * 1024 * 1024,
24+
KernelVersion: "5.15",
25+
},
26+
}, {
27+
AgentId: "id2",
28+
Lease: stackstate_api.AGENTLEASE_LIMITED,
29+
LeaseUntilEpochMs: 0,
30+
RegisteredEpochMs: 0,
31+
AgentData: nil,
32+
},
33+
}
34+
)
35+
36+
func TestAgentList(t *testing.T) {
37+
cli := di.NewMockDeps(t)
38+
cmd := ListCommand(&cli.Deps)
39+
40+
cli.MockClient.ApiMocks.AgentRegistrationsApi.AllAgentRegistrationsResponse.Result = stackstate_api.AgentRegistrations{
41+
Agents: SomeAgentRegistrations,
42+
}
43+
44+
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd)
45+
46+
assert.Len(t, *cli.MockClient.ApiMocks.AgentRegistrationsApi.AllAgentRegistrationsCalls, 1)
47+
48+
nulTime := time.UnixMilli(0).Format("2006-01-02 15:04:05 MST")
49+
50+
expectedTable := []printer.TableData{
51+
{
52+
Header: []string{"Host", "Lease", "Registered", "Last Lease", "CPUS", "Memory", "Platform", "Kernel"},
53+
Data: [][]interface{}{
54+
{"id1", stackstate_api.AGENTLEASE_ACTIVE, nulTime, nulTime, "4", "16MB", "platform", "5.15"},
55+
{"id2", stackstate_api.AGENTLEASE_LIMITED, nulTime, nulTime, "0", "0MB", "", ""},
56+
},
57+
},
58+
}
59+
60+
assert.Equal(t, expectedTable, *cli.MockPrinter.TableCalls)
61+
62+
di.ExecuteCommandWithContextUnsafe(&cli.Deps, cmd, "-o", "json")
63+
64+
assert.Len(t, *cli.MockClient.ApiMocks.AgentRegistrationsApi.AllAgentRegistrationsCalls, 2)
65+
66+
expectedJson := []map[string]interface{}{
67+
{
68+
"agents": SomeAgentRegistrations,
69+
},
70+
}
71+
72+
assert.Equal(t, expectedJson, *cli.MockPrinter.PrintJsonCalls)
73+
}

cmd/sts.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func STSCommand(cli *di.Deps) *cobra.Command {
2929
cmd.AddCommand(TopicCommand(cli))
3030
cmd.AddCommand(TopologySyncCommand(cli))
3131
cmd.AddCommand(IngestionApiKeyCommand(cli))
32+
cmd.AddCommand(AgentCommand(cli))
3233

3334
return cmd
3435
}

flake.lock

Lines changed: 42 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
{
2+
description = "StackState CLI";
3+
4+
nixConfig.bash-prompt = "STS CLI 2 $ ";
5+
6+
inputs = {
7+
nixpkgs.url = "github:nixos/nixpkgs";
8+
flake-utils.url = "github:numtide/flake-utils";
9+
};
10+
11+
outputs = { self, nixpkgs, flake-utils }:
12+
flake-utils.lib.eachDefaultSystem (system:
13+
let
14+
pkgs = import nixpkgs { inherit system; overlays = [ ]; };
15+
pkgs-linux = import nixpkgs { system = "x86_64-linux"; overlays = [ ]; };
16+
17+
# Dependencies used for both development and CI/CD
18+
sharedDeps = pkgs: (with pkgs; [
19+
bash
20+
go_1_19
21+
gotools
22+
diffutils # Required for golangci-lint
23+
golangci-lint
24+
openapi-generator-cli
25+
]);
26+
27+
# Dependencies used only by CI/CD
28+
ciDeps = pkgs: (with pkgs; [
29+
git
30+
cacert
31+
gcc
32+
coreutils-full
33+
goreleaser
34+
awscli
35+
docker
36+
]);
37+
38+
darwinDevShellExtraDeps = pkgs: pkgs.lib.optionals pkgs.stdenv.isDarwin (with pkgs.darwin.apple_sdk_11_0; [
39+
Libsystem
40+
IOKit
41+
]);
42+
in {
43+
44+
devShells = {
45+
dev = pkgs.mkShell {
46+
buildInputs = sharedDeps(pkgs) ++ darwinDevShellExtraDeps(pkgs);
47+
};
48+
49+
ci = pkgs.mkShell {
50+
buildInputs = sharedDeps(pkgs) ++ ciDeps(pkgs);
51+
};
52+
};
53+
54+
devShell = self.devShells."${system}".dev;
55+
56+
packages = {
57+
sts = pkgs.buildGo119Module {
58+
pname = "sts";
59+
version = "2.0.0";
60+
61+
src = ./.;
62+
63+
# This hash locks the dependencies of this package.
64+
# Change it to the provided when the go dependencies change.
65+
# See https://www.tweag.io/blog/2021-03-04-gomod2nix/ for details.
66+
#
67+
# NOTE In case if your build fails due to incosistency in vendor modules
68+
# Comment out the real hash and uncomment the fake one then on next `nix build .` run
69+
# you will get a new real hash which can be used here.
70+
#
71+
# vendorSha256 = pkgs.lib.fakeSha256;
72+
vendorSha256 = "sha256-aXTDHT1N+4Qpkuxb8vvBvP2VPyS5ofCgX6XFhJ5smUQ=";
73+
74+
postInstall = ''
75+
mv $out/bin/stackstate-cli2 $out/bin/sts
76+
'';
77+
};
78+
79+
ci-image = pkgs.dockerTools.buildImage {
80+
name = "stackstate-cli2-ci";
81+
tag = "latest";
82+
created = "now";
83+
84+
contents = sharedDeps(pkgs-linux) ++ ciDeps(pkgs-linux);
85+
86+
config = {
87+
Env = [
88+
"GIT_SSL_CAINFO=/etc/ssl/certs/ca-bundle.crt"
89+
"SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt"
90+
];
91+
92+
# Required to make golangci-lint work.
93+
Volumes = {
94+
"/tmp" = {};
95+
};
96+
};
97+
};
98+
99+
default = self.packages."${system}".sts;
100+
};
101+
102+
apps = {
103+
sts = {
104+
type = "app";
105+
program = "${self.packages."${system}".sts}/bin/sts";
106+
};
107+
108+
default = self.apps."${system}".sts;
109+
};
110+
});
111+
}

0 commit comments

Comments
 (0)