Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/cli. OpenStatus CLI www.openstatus.dev
Something went wrong. Try again.
Go
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243package monitors
import ( "context" "errors" "fmt" "net/http" "os" "strconv"
"buf.build/gen/go/openstatus/api/connectrpc/gosimple/openstatus/monitor/v1/monitorv1connect" monitorv1 "buf.build/gen/go/openstatus/api/protocolbuffers/go/openstatus/monitor/v1" "github.com/urfave/cli/v3"
"github.com/openstatusHQ/cli/internal/api" "github.com/openstatusHQ/cli/internal/auth" output "github.com/openstatusHQ/cli/internal/cli" "github.com/openstatusHQ/cli/internal/config")
// CreateMonitor creates a monitor using the SDK, dispatching to the appropriate typefunc CreateMonitor(ctx context.Context, httpClient *http.Client, apiKey string, monitor config.Monitor) (Monitor, error) { client := NewMonitorClientWithHTTPClient(httpClient, apiKey)
switch monitor.Kind { case config.HTTP: return CreateHTTPMonitor(ctx, client, monitor) case config.TCP: return CreateTCPMonitor(ctx, client, monitor) case config.ICMP: return CreateICMPMonitor(ctx, client, monitor) default: return Monitor{}, fmt.Errorf("unsupported monitor kind: %s", monitor.Kind) }}
// CreateHTTPMonitor creates an HTTP monitor using the SDKfunc CreateHTTPMonitor(ctx context.Context, client monitorv1connect.MonitorServiceClient, monitor config.Monitor) (Monitor, error) { req := &monitorv1.CreateHTTPMonitorRequest{ Monitor: configToHTTPMonitor(monitor), }
resp, err := client.CreateHTTPMonitor(ctx, req) if err != nil { return Monitor{}, fmt.Errorf("failed to create HTTP monitor: %w", err) }
return httpMonitorToLocal(resp.GetMonitor())}
// CreateTCPMonitor creates a TCP monitor using the SDKfunc CreateTCPMonitor(ctx context.Context, client monitorv1connect.MonitorServiceClient, monitor config.Monitor) (Monitor, error) { tcpMonitor, err := configToTCPMonitor(monitor) if err != nil { return Monitor{}, err } req := &monitorv1.CreateTCPMonitorRequest{ Monitor: tcpMonitor, }
resp, err := client.CreateTCPMonitor(ctx, req) if err != nil { return Monitor{}, fmt.Errorf("failed to create TCP monitor: %w", err) }
return tcpMonitorToLocal(resp.GetMonitor())}
// CreateICMPMonitor creates an ICMP monitor using the SDKfunc CreateICMPMonitor(ctx context.Context, client monitorv1connect.MonitorServiceClient, monitor config.Monitor) (Monitor, error) { icmpMonitor, err := configToICMPMonitor(monitor) if err != nil { return Monitor{}, err } req := &monitorv1.CreateICMPMonitorRequest{ Monitor: icmpMonitor, }
resp, err := client.CreateICMPMonitor(ctx, req) if err != nil { return Monitor{}, fmt.Errorf("failed to create ICMP monitor: %w", err) }
return icmpMonitorToLocal(resp.GetMonitor())}
func httpMonitorToLocal(m *monitorv1.HTTPMonitor) (Monitor, error) { id, err := strconv.Atoi(m.GetId()) if err != nil { return Monitor{}, fmt.Errorf("invalid monitor ID %q: %w", m.GetId(), err) }
var headers []Header for _, h := range m.GetHeaders() { headers = append(headers, Header{Key: h.GetKey(), Value: h.GetValue()}) }
var assertions []Assertion for _, a := range m.GetStatusCodeAssertions() { assertions = append(assertions, Assertion{ Type: "status_code", Compare: string(convertNumberComparator(a.GetComparator())), Target: int(a.GetTarget()), }) } for _, a := range m.GetBodyAssertions() { assertions = append(assertions, Assertion{ Type: "text_body", Compare: string(convertStringComparator(a.GetComparator())), Target: a.GetTarget(), }) } for _, a := range m.GetHeaderAssertions() { assertions = append(assertions, Assertion{ Type: "header", Compare: string(convertStringComparator(a.GetComparator())), Target: a.GetTarget(), Key: a.GetKey(), }) }
return Monitor{ ID: id, Name: m.GetName(), Description: m.GetDescription(), URL: m.GetUrl(), Periodicity: periodicityToString(m.GetPeriodicity()), Method: httpMethodToString(m.GetMethod()), Regions: regionsToStrings(m.GetRegions()), PrivateLocationIDs: m.GetPrivateLocationIds(), Active: m.GetActive(), Public: m.GetPublic(), Timeout: int(m.GetTimeout()), DegradedAfter: int(m.GetDegradedAt()), Body: m.GetBody(), Headers: headers, Assertions: assertions, Retry: int(m.GetRetry()), JobType: "http", }, nil}
func tcpMonitorToLocal(m *monitorv1.TCPMonitor) (Monitor, error) { id, err := strconv.Atoi(m.GetId()) if err != nil { return Monitor{}, fmt.Errorf("invalid monitor ID %q: %w", m.GetId(), err) } return Monitor{ ID: id, Name: m.GetName(), Description: m.GetDescription(), URL: m.GetUri(), Periodicity: periodicityToString(m.GetPeriodicity()), Regions: regionsToStrings(m.GetRegions()), PrivateLocationIDs: m.GetPrivateLocationIds(), Active: m.GetActive(), Public: m.GetPublic(), Timeout: int(m.GetTimeout()), DegradedAfter: int(m.GetDegradedAt()), Retry: int(m.GetRetry()), JobType: "tcp", }, nil}
func GetMonitorCreateCmd() *cli.Command { monitorCreateCmd := cli.Command{ Name: "create", Usage: "Create monitors", Hidden: true, HideHelp: true, HideHelpCommand: true, Description: "Create the monitors defined in the openstatus.yaml file", UsageText: `openstatus monitors create openstatus monitors create --config custom.yaml -y`,
Action: func(ctx context.Context, cmd *cli.Command) error { apiKey, err := auth.ResolveAccessToken(cmd) if err != nil { return cli.Exit(err.Error(), 1) }
path := cmd.String("config")
if path != "" { if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) { return cli.Exit("Config does not exist", 1) } }
accept := cmd.Bool("auto-accept")
monitors, err := config.ReadOpenStatus(path) if err != nil { return cli.Exit("Unable to read config file", 1) }
if !accept { confirmed, err := output.AskForConfirmation(fmt.Sprintf("You are about to create %d monitors do you want to continue", len(monitors))) if err != nil { return cli.Exit(fmt.Sprintf("Failed to read input: %v", err), 1) } if !confirmed { return nil } } s := output.StartSpinner("Creating monitors...") for _, value := range monitors { _, err = CreateMonitor(ctx, api.DefaultHTTPClient, apiKey, value) if err != nil { output.StopSpinner(s) return cli.Exit("Unable to create monitor", 1) } } output.StopSpinner(s) fmt.Printf("%d monitors created successfully\n", len(monitors)) fmt.Println("Run 'openstatus monitors list' to see all monitors") return nil }, Flags: []cli.Flag{ &cli.StringFlag{ Name: "config", Usage: "The configuration file containing monitor information", Aliases: []string{"c"}, DefaultText: "openstatus.yaml", Value: "openstatus.yaml", }, &cli.StringFlag{ Name: "access-token", Usage: "OpenStatus API Access Token", Aliases: []string{"t"}, Sources: cli.EnvVars("OPENSTATUS_API_TOKEN"), }, &cli.BoolFlag{ Name: "auto-accept", Usage: "Automatically accept the prompt", Aliases: []string{"y"}, Required: false, }, }, } return &monitorCreateCmd}