Skip to content

Commit 53beaf9

Browse files
feat: add flags to set non-default endpoints for status command to enable use in kubernetes
1 parent 97fbd00 commit 53beaf9

File tree

8 files changed

+123
-58
lines changed

8 files changed

+123
-58
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ vendor:
3030
build:
3131
go build ./...
3232

33+
docker-image:
34+
env GOOS=linux GOARCH=arm64 go build -o observe-agent
35+
docker build -f packaging/docker/Dockerfile -t observe-agent:dev .
36+
3337
## test: Runs Go tests across all packages
3438
go-test: build
3539
go list -f '{{.Dir}}' -m | xargs go test -v ./...

internal/commands/diagnose/agentstatuscheck.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ type StatusTestResult struct {
1313
Error string
1414
}
1515

16-
func checkStatus(_ *viper.Viper) (bool, any, error) {
17-
data, err := status.GetStatusData()
16+
func checkStatus(v *viper.Viper) (bool, any, error) {
17+
data, err := status.GetStatusData(v.GetString(status.TelemetryEndpointFlag), v.GetString(status.HealthcheckEndpointFlag), v.GetString(status.HealthcheckPathFlag))
1818
if err != nil {
1919
return false, StatusTestResult{
2020
Passed: false,

internal/commands/diagnose/diagnose.go

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"os"
1010
"text/template"
1111

12+
"github.com/observeinc/observe-agent/internal/commands/status"
1213
"github.com/observeinc/observe-agent/internal/root"
1314
"github.com/spf13/cobra"
1415
"github.com/spf13/viper"
@@ -28,46 +29,49 @@ var diagnostics = []Diagnostic{
2829
authDiagnostic(),
2930
}
3031

31-
// diagnoseCmd represents the diagnose command
32-
var diagnoseCmd = &cobra.Command{
33-
Use: "diagnose",
34-
Short: "Run diagnostic checks.",
35-
Long: `This command runs diagnostic checks for various settings and configurations
32+
func NewDiagnoseCmd(v *viper.Viper) *cobra.Command {
33+
return &cobra.Command{
34+
Use: "diagnose",
35+
Short: "Run diagnostic checks.",
36+
Long: `This command runs diagnostic checks for various settings and configurations
3637
to attempt to identify issues that could cause the agent to function improperly.`,
37-
Run: func(cmd *cobra.Command, args []string) {
38-
v := viper.GetViper()
39-
fmt.Print("Running diagnosis checks...")
40-
var failedChecks []string
41-
for _, diagnostic := range diagnostics {
42-
fmt.Printf("\n\n\n%s\n==================\n", diagnostic.checkName)
43-
success, data, err := diagnostic.check(v)
44-
if !success {
45-
failedChecks = append(failedChecks, diagnostic.checkName)
38+
Run: func(cmd *cobra.Command, args []string) {
39+
fmt.Print("Running diagnosis checks...")
40+
var failedChecks []string
41+
for _, diagnostic := range diagnostics {
42+
fmt.Printf("\n\n\n%s\n==================\n", diagnostic.checkName)
43+
success, data, err := diagnostic.check(v)
44+
if !success {
45+
failedChecks = append(failedChecks, diagnostic.checkName)
46+
}
47+
if err != nil {
48+
fmt.Printf("⚠️ Failed to run check: %s\n", err.Error())
49+
continue
50+
}
51+
t := template.Must(template.
52+
New(diagnostic.templateName).
53+
ParseFS(diagnostic.templateFS, diagnostic.templateName))
54+
if err := t.ExecuteTemplate(os.Stdout, diagnostic.templateName, data); err != nil {
55+
fmt.Printf("⚠️ Failed to print output for check: %s\n", err.Error())
56+
continue
57+
}
4658
}
47-
if err != nil {
48-
fmt.Printf("⚠️ Failed to run check: %s\n", err.Error())
49-
continue
59+
if len(failedChecks) > 0 {
60+
fmt.Printf("\n\n\n❌ %d out of %d checks failed:\n", len(failedChecks), len(diagnostics))
61+
for _, check := range failedChecks {
62+
fmt.Printf(" - %s\n", check)
63+
}
64+
os.Exit(1)
65+
} else {
66+
fmt.Printf("\n✅ All %d checks passed!\n", len(diagnostics))
5067
}
51-
t := template.Must(template.
52-
New(diagnostic.templateName).
53-
ParseFS(diagnostic.templateFS, diagnostic.templateName))
54-
if err := t.ExecuteTemplate(os.Stdout, diagnostic.templateName, data); err != nil {
55-
fmt.Printf("⚠️ Failed to print output for check: %s\n", err.Error())
56-
continue
57-
}
58-
}
59-
if len(failedChecks) > 0 {
60-
fmt.Printf("\n\n\n❌ %d out of %d checks failed:\n", len(failedChecks), len(diagnostics))
61-
for _, check := range failedChecks {
62-
fmt.Printf(" - %s\n", check)
63-
}
64-
os.Exit(1)
65-
} else {
66-
fmt.Printf("\n✅ All %d checks passed!\n", len(diagnostics))
67-
}
68-
},
68+
},
69+
}
6970
}
7071

7172
func init() {
73+
v := viper.GetViper()
74+
diagnoseCmd := NewDiagnoseCmd(v)
75+
status.RegisterStatusFlags(diagnoseCmd, v)
7276
root.RootCmd.AddCommand(diagnoseCmd)
7377
}

internal/commands/status/flags.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package status
2+
3+
import (
4+
"github.com/spf13/viper"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
const (
10+
TelemetryEndpointFlag = "telemetry-endpoint"
11+
HealthcheckEndpointFlag = "healthcheck-endpoint"
12+
HealthcheckPathFlag = "healthcheck-path"
13+
)
14+
15+
var (
16+
telemetryEndpoint string
17+
healthcheckEndpoint string
18+
healthcheckPath string
19+
)
20+
21+
func RegisterStatusFlags(cmd *cobra.Command, v *viper.Viper) {
22+
// Use persistent flags and fixed variables so these flags can be used in multiple subcommands
23+
pf := cmd.PersistentFlags()
24+
pf.StringVar(&telemetryEndpoint, TelemetryEndpointFlag, "http://localhost:8888", "Endpoint the observe-agent has exposed for internal telemetry data")
25+
pf.StringVar(&healthcheckEndpoint, HealthcheckEndpointFlag, "http://localhost:13133", "Endpoint the observe-agent has configured for the health check connector")
26+
pf.StringVar(&healthcheckPath, HealthcheckPathFlag, "/status", "Path the observe-agent has configured for the health check connector")
27+
v.BindPFlag(TelemetryEndpointFlag, pf.Lookup(TelemetryEndpointFlag))
28+
v.BindPFlag(HealthcheckEndpointFlag, pf.Lookup(HealthcheckEndpointFlag))
29+
v.BindPFlag(HealthcheckPathFlag, pf.Lookup(HealthcheckPathFlag))
30+
}

internal/commands/status/status.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/observeinc/observe-agent/internal/connections"
1212
"github.com/observeinc/observe-agent/internal/root"
1313
"github.com/spf13/cobra"
14+
"github.com/spf13/viper"
1415
)
1516

1617
const statusTemplate = "status.tmpl"
@@ -20,22 +21,26 @@ var (
2021
statusTemplateFS embed.FS
2122
)
2223

23-
// statusCmd represents the status command
24-
var statusCmd = &cobra.Command{
25-
Use: "status",
26-
Short: "Display status of agent",
27-
Long: ``,
28-
Run: func(cmd *cobra.Command, args []string) {
29-
getStatusFromTemplate()
30-
},
24+
func NewStatusCmd(v *viper.Viper) *cobra.Command {
25+
return &cobra.Command{
26+
Use: "status",
27+
Short: "Display status of agent",
28+
Long: ``,
29+
Run: func(cmd *cobra.Command, args []string) {
30+
getStatusFromTemplate(v)
31+
},
32+
}
3133
}
3234

3335
func init() {
36+
v := viper.GetViper()
37+
statusCmd := NewStatusCmd(v)
38+
RegisterStatusFlags(statusCmd, v)
3439
root.RootCmd.AddCommand(statusCmd)
3540
}
3641

37-
func getStatusFromTemplate() error {
38-
data, err := GetStatusData()
42+
func getStatusFromTemplate(v *viper.Viper) error {
43+
data, err := GetStatusData(v.GetString(TelemetryEndpointFlag), v.GetString(HealthcheckEndpointFlag), v.GetString(HealthcheckPathFlag))
3944
if err != nil {
4045
return err
4146
}

internal/commands/status/statusRetriever.go

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package status
22

33
import (
4+
"errors"
45
"fmt"
56
"net/http"
7+
"net/url"
68
"os"
79
"strconv"
810
"time"
@@ -68,16 +70,26 @@ func bToMb(b float32) float32 {
6870
return b / 1024 / 1024
6971
}
7072

71-
func GetAgentStatusFromHealthcheck(baseURL string) (AgentStatus, error) {
72-
URL := fmt.Sprintf("%s/status", baseURL)
73+
func GetAgentStatusFromHealthcheck(baseURL string, path string) (AgentStatus, error) {
74+
if len(path) == 0 || len(baseURL) == 0 {
75+
return NotRunning, errors.New("health_check endpoint and path must be provided")
76+
}
77+
if baseURL[len(baseURL)-1] == '/' {
78+
baseURL = baseURL[:len(baseURL)-1]
79+
}
80+
URL, err := url.JoinPath(baseURL, path)
81+
if err != nil {
82+
return NotRunning, err
83+
}
84+
7385
c := &http.Client{}
7486
req, err := http.NewRequest("GET", URL, nil)
7587
if err != nil {
76-
return NotRunning, nil
88+
return NotRunning, err
7789
}
7890
resp, err := c.Do(req)
7991
if err != nil {
80-
return NotRunning, nil
92+
return NotRunning, err
8193
}
8294
if resp.StatusCode == 200 {
8395
return Running, nil
@@ -95,7 +107,16 @@ func getMetricsSum(metrics []*io_prometheus_client.Metric) float64 {
95107
}
96108

97109
func GetAgentMetricsFromEndpoint(baseURL string) (*AgentMetrics, error) {
98-
URL := fmt.Sprintf("%s/metrics", baseURL)
110+
if len(baseURL) == 0 {
111+
return nil, errors.New("metrics endpoint must be provided")
112+
}
113+
if baseURL[len(baseURL)-1] == '/' {
114+
baseURL = baseURL[:len(baseURL)-1]
115+
}
116+
URL, err := url.JoinPath(baseURL, "/metrics")
117+
if err != nil {
118+
return nil, err
119+
}
99120
c := &http.Client{}
100121
req, err := http.NewRequest("GET", URL, nil)
101122
if err != nil {
@@ -176,10 +197,10 @@ func GetAgentMetricsFromEndpoint(baseURL string) (*AgentMetrics, error) {
176197
return &agentMets, nil
177198
}
178199

179-
func GetStatusData() (*StatusData, error) {
180-
agentMets, err := GetAgentMetricsFromEndpoint("http://localhost:8888")
200+
func GetStatusData(telemetryEndpoint string, healthcheckEndpoint string, healthcheckPath string) (*StatusData, error) {
201+
agentMets, err := GetAgentMetricsFromEndpoint(telemetryEndpoint)
181202
if err != nil {
182-
fmt.Println("Error getting agent metrics: ", err)
203+
fmt.Fprintln(os.Stderr, "Error getting agent metrics: ", err)
183204
agentMets = &AgentMetrics{}
184205
}
185206
hostInfo, err := host.Info()
@@ -195,8 +216,9 @@ func GetStatusData() (*StatusData, error) {
195216
if err != nil {
196217
uptime = time.Duration(0)
197218
}
198-
status, err := GetAgentStatusFromHealthcheck("http://localhost:13133")
219+
status, err := GetAgentStatusFromHealthcheck(healthcheckEndpoint, healthcheckPath)
199220
if err != nil {
221+
fmt.Fprintln(os.Stderr, "Error receiving data from agent health check: ", err)
200222
status = NotRunning
201223
}
202224

internal/commands/status/statusretriever_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func TestGetAgentStatusFromHealthcheck(t *testing.T) {
3434
}))
3535
defer server.Close()
3636

37-
status, err := GetAgentStatusFromHealthcheck(server.URL)
37+
status, err := GetAgentStatusFromHealthcheck(server.URL, "/status")
3838
if err != nil {
3939
t.Error(err)
4040
}

internal/connections/confighandler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func SetEnvVars() error {
6666
// Ensure the collector url does not end with a slash for consistency. This will allow endpoints to be configured like:
6767
// "${env:OBSERVE_COLLECTOR_URL}/v1/kubernetes/v1/entity"
6868
// without worrying about a double slash.
69-
if collector_url[len(collector_url)-1] == '/' {
69+
if len(collector_url) != 0 && collector_url[len(collector_url)-1] == '/' {
7070
collector_url = collector_url[:len(collector_url)-1]
7171
}
7272
otelEndpoint, err := url.JoinPath(collector_url, "/v2/otel")

0 commit comments

Comments
 (0)