@@ -11,7 +11,6 @@ import (
1111 "strconv"
1212
1313 "go.mondoo.com/mql/v13/llx"
14- "go.mondoo.com/mql/v13/providers/grafana/connection"
1514)
1615
1716// grafanaServiceAccountJSON mirrors one element of the /api/serviceaccounts/search response.
@@ -27,38 +26,61 @@ type grafanaServiceAccountJSON struct {
2726
2827// grafanaServiceAccountsResponse wraps the paginated service accounts endpoint.
2928type grafanaServiceAccountsResponse struct {
30- ServiceAccounts []grafanaServiceAccountJSON `json:"serviceAccounts"`
29+ TotalCount int `json:"totalCount"`
30+ ServiceAccounts []grafanaServiceAccountJSON `json:"serviceAccounts"`
31+ Page int `json:"page"`
32+ PerPage int `json:"perPage"`
3133}
3234
3335// grafanaTokenJSON mirrors one element of the /api/serviceaccounts/{id}/tokens response.
3436type grafanaTokenJSON struct {
35- ID int `json:"id"`
36- Name string `json:"name"`
37- Created string `json:"created"`
38- Expiration string `json:"expiration"`
39- HasExpired bool `json:"hasExpired"`
40- SecondsTillExpiration float64 `json:"secondsUntilExpiration"`
41- IsRevoked bool `json:"isRevoked"`
37+ ID int `json:"id"`
38+ Name string `json:"name"`
39+ Created string `json:"created"`
40+ Expiration string `json:"expiration"`
41+ HasExpired bool `json:"hasExpired"`
42+ SecondsTillExpiration float64 `json:"secondsUntilExpiration"`
43+ IsRevoked bool `json:"isRevoked"`
4244}
4345
46+ const serviceAccountPageSize = 1000
47+
4448func (g * mqlGrafana ) serviceAccounts () ([]interface {}, error ) {
45- conn := g .MqlRuntime .Connection .(* connection.GrafanaConnection )
46- resp , err := conn .Get (context .Background (), "/api/serviceaccounts/search?perpage=1000&page=1" )
49+ conn , err := grafanaConnection (g .MqlRuntime )
4750 if err != nil {
4851 return nil , err
4952 }
50- defer resp .Body .Close ()
51- if resp .StatusCode != http .StatusOK {
52- return nil , fmt .Errorf ("grafana: GET /api/serviceaccounts/search returned status %d" , resp .StatusCode )
53- }
5453
55- var result grafanaServiceAccountsResponse
56- if err := json .NewDecoder (resp .Body ).Decode (& result ); err != nil {
57- return nil , fmt .Errorf ("grafana: decoding /api/serviceaccounts/search response: %w" , err )
54+ // Paginate through all service accounts. The API returns at most perpage
55+ // results per request; we stop when we've collected totalCount or the
56+ // page returns fewer results than requested.
57+ var allSAs []grafanaServiceAccountJSON
58+ for page := 1 ; ; page ++ {
59+ path := fmt .Sprintf ("/api/serviceaccounts/search?perpage=%d&page=%d" , serviceAccountPageSize , page )
60+ resp , err := conn .Get (context .Background (), path )
61+ if err != nil {
62+ return nil , err
63+ }
64+ defer resp .Body .Close ()
65+ if resp .StatusCode != http .StatusOK {
66+ return nil , fmt .Errorf ("grafana: GET /api/serviceaccounts/search returned status %d" , resp .StatusCode )
67+ }
68+
69+ var result grafanaServiceAccountsResponse
70+ if err := json .NewDecoder (resp .Body ).Decode (& result ); err != nil {
71+ return nil , fmt .Errorf ("grafana: decoding /api/serviceaccounts/search response: %w" , err )
72+ }
73+
74+ allSAs = append (allSAs , result .ServiceAccounts ... )
75+
76+ // Stop when we've fetched everything or the page was not full.
77+ if len (allSAs ) >= result .TotalCount || len (result .ServiceAccounts ) < serviceAccountPageSize {
78+ break
79+ }
5880 }
5981
60- list := make ([]interface {}, 0 , len (result . ServiceAccounts ))
61- for _ , sa := range result . ServiceAccounts {
82+ list := make ([]interface {}, 0 , len (allSAs ))
83+ for _ , sa := range allSAs {
6284 res , err := CreateResource (g .MqlRuntime , "grafana.serviceAccount" , map [string ]* llx.RawData {
6385 "id" : llx .IntData (int64 (sa .ID )),
6486 "orgId" : llx .IntData (int64 (sa .OrgID )),
@@ -81,7 +103,10 @@ func (g *mqlGrafanaServiceAccount) id() (string, error) {
81103}
82104
83105func (g * mqlGrafanaServiceAccount ) tokens () ([]interface {}, error ) {
84- conn := g .MqlRuntime .Connection .(* connection.GrafanaConnection )
106+ conn , err := grafanaConnection (g .MqlRuntime )
107+ if err != nil {
108+ return nil , err
109+ }
85110 saID := g .Id .Data
86111 path := "/api/serviceaccounts/" + strconv .FormatInt (saID , 10 ) + "/tokens"
87112
0 commit comments