Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/cli. OpenStatus CLI www.openstatus.dev
cli cli-app synthetic-monitoring
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164package terraform
import ( "context" "fmt" "net/http" "os"
"buf.build/gen/go/openstatus/api/connectrpc/gosimple/openstatus/monitor/v1/monitorv1connect" "buf.build/gen/go/openstatus/api/connectrpc/gosimple/openstatus/notification/v1/notificationv1connect" "buf.build/gen/go/openstatus/api/connectrpc/gosimple/openstatus/private_location/v1/private_locationv1connect" "buf.build/gen/go/openstatus/api/connectrpc/gosimple/openstatus/status_page/v1/status_pagev1connect" monitorv1 "buf.build/gen/go/openstatus/api/protocolbuffers/go/openstatus/monitor/v1" notificationv1 "buf.build/gen/go/openstatus/api/protocolbuffers/go/openstatus/notification/v1" private_locationv1 "buf.build/gen/go/openstatus/api/protocolbuffers/go/openstatus/private_location/v1" status_pagev1 "buf.build/gen/go/openstatus/api/protocolbuffers/go/openstatus/status_page/v1" "connectrpc.com/connect"
"github.com/openstatusHQ/cli/internal/api")
const privateLocationPageSize = 100
type StatusPageData struct { Page *status_pagev1.StatusPage Components []*status_pagev1.PageComponent Groups []*status_pagev1.PageComponentGroup}
type WorkspaceData struct { HTTPMonitors []*monitorv1.HTTPMonitor TCPMonitors []*monitorv1.TCPMonitor DNSMonitors []*monitorv1.DNSMonitor ICMPMonitors []*monitorv1.ICMPMonitor Notifications []*notificationv1.Notification StatusPages []StatusPageData PrivateLocations []*private_locationv1.PrivateLocation}
func FetchWorkspaceData(ctx context.Context, apiKey string) (*WorkspaceData, error) { return FetchWorkspaceDataWithHTTPClient(ctx, api.DefaultHTTPClient, apiKey)}
func FetchWorkspaceDataWithHTTPClient(ctx context.Context, httpClient *http.Client, apiKey string) (*WorkspaceData, error) { interceptor := connect.WithInterceptors(api.NewAuthInterceptor(apiKey)) protoJSON := connect.WithProtoJSON()
data := &WorkspaceData{}
// Monitors monitorClient := monitorv1connect.NewMonitorServiceClient(httpClient, api.ConnectBaseURL, interceptor, protoJSON) monitorResp, err := monitorClient.ListMonitors(ctx, &monitorv1.ListMonitorsRequest{}) if err != nil { return nil, fmt.Errorf("failed to list monitors: %w", err) } data.HTTPMonitors = monitorResp.GetHttpMonitors() data.TCPMonitors = monitorResp.GetTcpMonitors() data.DNSMonitors = monitorResp.GetDnsMonitors() data.ICMPMonitors = monitorResp.GetIcmpMonitors()
// Notifications notifClient := notificationv1connect.NewNotificationServiceClient(httpClient, api.ConnectBaseURL, interceptor, protoJSON) notifResp, err := notifClient.ListNotifications(ctx, ¬ificationv1.ListNotificationsRequest{}) if err != nil { return nil, fmt.Errorf("failed to list notifications: %w", err) } for _, summary := range notifResp.GetNotifications() { req := ¬ificationv1.GetNotificationRequest{} req.SetId(summary.GetId()) resp, err := notifClient.GetNotification(ctx, req) if err != nil { return nil, fmt.Errorf("failed to get notification %s: %w", summary.GetId(), err) } data.Notifications = append(data.Notifications, resp.GetNotification()) }
// Status Pages pageClient := status_pagev1connect.NewStatusPageServiceClient(httpClient, api.ConnectBaseURL, interceptor, protoJSON) pageResp, err := pageClient.ListStatusPages(ctx, &status_pagev1.ListStatusPagesRequest{}) if err != nil { return nil, fmt.Errorf("failed to list status pages: %w", err) } for _, summary := range pageResp.GetStatusPages() { req := &status_pagev1.GetStatusPageContentRequest{} req.SetId(summary.GetId()) resp, err := pageClient.GetStatusPageContent(ctx, req) if err != nil { return nil, fmt.Errorf("failed to get status page %s: %w", summary.GetId(), err) } data.StatusPages = append(data.StatusPages, StatusPageData{ Page: resp.GetStatusPage(), Components: resp.GetComponents(), Groups: resp.GetGroups(), }) }
// Private Locations plClient := private_locationv1connect.NewPrivateLocationServiceClient(httpClient, api.ConnectBaseURL, interceptor, protoJSON) locations, err := fetchPrivateLocations(ctx, plClient) switch { case err == nil: data.PrivateLocations = locations case isFeatureUnavailable(err): // Partial results are dropped on purpose: Terraform owns monitor_ids, so // an incomplete set would detach monitors on the next apply. fmt.Fprintf(os.Stderr, "warning: skipping private locations — %v\n", err) default: return nil, fmt.Errorf("failed to fetch private locations: %w", err) }
return data, nil}
// fetchPrivateLocations returns every private location with its monitor_ids.// ListPrivateLocations only reports monitor_count, so each summary needs a Get.// Errors are returned unwrapped so the caller can inspect the Connect code.func fetchPrivateLocations(ctx context.Context, client private_locationv1connect.PrivateLocationServiceClient) ([]*private_locationv1.PrivateLocation, error) { var locations []*private_locationv1.PrivateLocation
for offset := int32(0); ; { listReq := &private_locationv1.ListPrivateLocationsRequest{} listReq.SetLimit(privateLocationPageSize) listReq.SetOffset(offset)
listResp, err := client.ListPrivateLocations(ctx, listReq) if err != nil { return nil, err }
summaries := listResp.GetPrivateLocations() if len(summaries) == 0 { break }
for _, summary := range summaries { getReq := &private_locationv1.GetPrivateLocationRequest{} getReq.SetId(summary.GetId()) getResp, err := client.GetPrivateLocation(ctx, getReq) if err != nil { return nil, err } locations = append(locations, getResp.GetPrivateLocation()) }
offset += int32(len(summaries)) if offset >= listResp.GetTotalSize() { break } }
return locations, nil}
// isFeatureUnavailable reports whether the workspace simply cannot use private// locations, as opposed to a failure worth aborting the whole export for.func isFeatureUnavailable(err error) bool { switch connect.CodeOf(err) { case connect.CodePermissionDenied, connect.CodeUnimplemented: return true default: return false }}