github.com/kyma-project/kyma-environment-broker@v0.0.1/common/runtime/client.go (about) 1 package runtime 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "net/http" 9 "net/url" 10 "strconv" 11 12 "github.com/kyma-project/kyma-environment-broker/common/pagination" 13 ) 14 15 const defaultPageSize = 100 16 17 // Client is the interface to interact with the KEB /runtimes API as an HTTP client using OIDC ID token in JWT format. 18 type Client interface { 19 ListRuntimes(params ListParameters) (RuntimesPage, error) 20 } 21 22 type client struct { 23 url string 24 httpClient *http.Client 25 } 26 27 // NewClient constructs and returns new Client for KEB /runtimes API 28 // It takes the following arguments: 29 // - url : base url of all KEB APIs, e.g. https://kyma-env-broker.kyma.local 30 // - httpClient : underlying HTTP client used for API call to KEB 31 func NewClient(url string, httpClient *http.Client) Client { 32 return &client{ 33 url: url, 34 httpClient: httpClient, 35 } 36 } 37 38 // ListRuntimes fetches the runtimes from KEB according to the given parameters. 39 // If params.Page or params.PageSize is not set (zero), the client will fetch and return all runtimes. 40 func (c *client) ListRuntimes(params ListParameters) (RuntimesPage, error) { 41 runtimes := RuntimesPage{} 42 getAll := false 43 fetchedAll := false 44 if params.Page == 0 || params.PageSize == 0 { 45 getAll = true 46 params.Page = 1 47 params.PageSize = defaultPageSize 48 } 49 50 for !fetchedAll { 51 req, err := http.NewRequest("GET", fmt.Sprintf("%s/runtimes", c.url), nil) 52 if err != nil { 53 return runtimes, fmt.Errorf("while creating request: %w", err) 54 } 55 setQuery(req.URL, params) 56 57 resp, err := c.httpClient.Do(req) 58 if err != nil { 59 return runtimes, fmt.Errorf("while calling %s: %w", req.URL.String(), err) 60 } 61 62 // Drain response body and close, return error to context if there isn't any. 63 defer func() { 64 derr := drainResponseBody(resp.Body) 65 if err == nil { 66 err = derr 67 } 68 cerr := resp.Body.Close() 69 if err == nil { 70 err = cerr 71 } 72 }() 73 74 if resp.StatusCode != http.StatusOK { 75 return runtimes, fmt.Errorf("calling %s returned %d (%s) status", req.URL.String(), resp.StatusCode, resp.Status) 76 } 77 78 var rp RuntimesPage 79 decoder := json.NewDecoder(resp.Body) 80 err = decoder.Decode(&rp) 81 if err != nil { 82 return runtimes, fmt.Errorf("while decoding response body: %w", err) 83 } 84 85 runtimes.TotalCount = rp.TotalCount 86 runtimes.Count += rp.Count 87 runtimes.Data = append(runtimes.Data, rp.Data...) 88 if getAll { 89 params.Page++ 90 fetchedAll = runtimes.Count >= runtimes.TotalCount 91 } else { 92 fetchedAll = true 93 } 94 } 95 96 return runtimes, nil 97 } 98 99 func setQuery(url *url.URL, params ListParameters) { 100 query := url.Query() 101 query.Add(pagination.PageParam, strconv.Itoa(params.Page)) 102 query.Add(pagination.PageSizeParam, strconv.Itoa(params.PageSize)) 103 if params.OperationDetail != "" { 104 query.Add(OperationDetailParam, string(params.OperationDetail)) 105 } 106 if params.KymaConfig { 107 query.Add(KymaConfigParam, "true") 108 } 109 if params.ClusterConfig { 110 query.Add(ClusterConfigParam, "true") 111 } 112 if params.Expired { 113 query.Add(ExpiredParam, "true") 114 } 115 setParamList(query, GlobalAccountIDParam, params.GlobalAccountIDs) 116 setParamList(query, SubAccountIDParam, params.SubAccountIDs) 117 setParamList(query, InstanceIDParam, params.InstanceIDs) 118 setParamList(query, RuntimeIDParam, params.RuntimeIDs) 119 setParamList(query, RegionParam, params.Regions) 120 setParamList(query, ShootParam, params.Shoots) 121 setParamList(query, PlanParam, params.Plans) 122 for _, s := range params.States { 123 query.Add(StateParam, string(s)) 124 } 125 url.RawQuery = query.Encode() 126 } 127 128 func setParamList(query url.Values, key string, values []string) { 129 for _, value := range values { 130 query.Add(key, value) 131 } 132 } 133 134 func drainResponseBody(body io.Reader) error { 135 if body == nil { 136 return nil 137 } 138 _, err := io.Copy(ioutil.Discard, io.LimitReader(body, 4096)) 139 return err 140 }