mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-19 16:27:37 +00:00
117 lines
3.2 KiB
Go
117 lines
3.2 KiB
Go
package pulsecli
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
type FleetDeps struct {
|
|
HTTPClient HTTPDoer
|
|
Getenv func(string) string
|
|
}
|
|
|
|
type fleetConnectionsOptions struct {
|
|
APIURL string
|
|
Token string
|
|
}
|
|
|
|
type fleetConnectionsResponse struct {
|
|
Connections []json.RawMessage `json:"connections"`
|
|
Systems []json.RawMessage `json:"systems,omitempty"`
|
|
}
|
|
|
|
func newFleetCmd(deps *FleetDeps) *cobra.Command {
|
|
fleetCmd := &cobra.Command{
|
|
Use: "fleet",
|
|
Short: "Inspect canonical Pulse fleet state",
|
|
}
|
|
fleetCmd.AddCommand(newFleetConnectionsCmd(deps))
|
|
return fleetCmd
|
|
}
|
|
|
|
func newFleetConnectionsCmd(deps *FleetDeps) *cobra.Command {
|
|
opts := fleetConnectionsOptions{
|
|
APIURL: strings.TrimSpace(fleetGetenv(deps, "PULSE_API_URL")),
|
|
Token: strings.TrimSpace(fleetGetenv(deps, "PULSE_API_TOKEN")),
|
|
}
|
|
if opts.APIURL == "" {
|
|
opts.APIURL = defaultPulseAPIURL
|
|
}
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "connections",
|
|
Short: "List canonical fleet connection rows",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return runFleetConnections(cmd, deps, opts)
|
|
},
|
|
}
|
|
cmd.Flags().StringVar(&opts.APIURL, "api-url", opts.APIURL, "Pulse server URL or /api base URL")
|
|
cmd.Flags().StringVar(&opts.Token, "token", opts.Token, "Pulse API token; defaults to PULSE_API_TOKEN")
|
|
return cmd
|
|
}
|
|
|
|
func runFleetConnections(cmd *cobra.Command, deps *FleetDeps, opts fleetConnectionsOptions) error {
|
|
token := strings.TrimSpace(opts.Token)
|
|
if token == "" {
|
|
return fmt.Errorf("api token is required (use --token or PULSE_API_TOKEN)")
|
|
}
|
|
|
|
endpoint, err := pulseAPIEndpoint(opts.APIURL, "/connections")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
httpReq, err := http.NewRequestWithContext(cmd.Context(), http.MethodGet, endpoint.String(), nil)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to build fleet connections request: %w", err)
|
|
}
|
|
httpReq.Header.Set("Accept", "application/json")
|
|
httpReq.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
resp, err := fleetHTTPClient(deps).Do(httpReq)
|
|
if err != nil {
|
|
return fmt.Errorf("fleet connections request failed: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
respBody, err := ReadBoundedHTTPBody(resp.Body, resp.ContentLength, maxPulseAPIResponseBytes, "fleet connections response")
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read fleet connections response: %w", err)
|
|
}
|
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
return apiStatusError("fleet connections request", resp.Status, respBody)
|
|
}
|
|
|
|
var connections fleetConnectionsResponse
|
|
if err := decodeJSONBytes(respBody, &connections); err != nil {
|
|
return fmt.Errorf("failed to decode fleet connections response: %w", err)
|
|
}
|
|
if connections.Connections == nil {
|
|
connections.Connections = []json.RawMessage{}
|
|
}
|
|
|
|
encoder := json.NewEncoder(cmd.OutOrStdout())
|
|
encoder.SetIndent("", " ")
|
|
if err := encoder.Encode(connections); err != nil {
|
|
return fmt.Errorf("failed to write fleet connections response: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func fleetHTTPClient(deps *FleetDeps) HTTPDoer {
|
|
if deps != nil {
|
|
return cliHTTPClient(deps.HTTPClient)
|
|
}
|
|
return cliHTTPClient(nil)
|
|
}
|
|
|
|
func fleetGetenv(deps *FleetDeps, key string) string {
|
|
if deps != nil {
|
|
return cliGetenv(deps.Getenv, key)
|
|
}
|
|
return cliGetenv(nil, key)
|
|
}
|