diff --git a/client.go b/client.go index a8bbf9a..82178df 100644 --- a/client.go +++ b/client.go @@ -3,13 +3,8 @@ package netboxapi import ( - "bytes" - "encoding/json" "fmt" - "io" - "net/http" - e "git.stinnesbeck.com/nils/errorhandler" transport "github.com/go-openapi/runtime/client" "github.com/netbox-community/go-netbox/v3/netbox/client" ) @@ -21,13 +16,6 @@ type NetBoxAPI struct { URL string } -type apiResponse struct { - Count int64 `json:"count"` - Next string `json:"next"` - Previous string `json:"previous"` - Results []any `json:"results"` -} - // NewNetBoxClient returns a client to NetBox at the given url, // using the provided token func NewNetBoxClient(token string, url string) (NetBoxAPI, error) { @@ -50,130 +38,3 @@ func NewNetBoxClient(token string, url string) (NetBoxAPI, error) { } return nb, nil } - -func (nb NetBoxAPI) handleRawPagination(url string) (*apiResponse, error) { - var response apiResponse - b, err := nb.rawNetBoxAPICall(url, http.MethodGet) - if err != nil { - return nil, e.FormatError("can't perform raw NetBox API call", err) - } - - // Unmarshal json into response - if err := json.Unmarshal(b, &response); err != nil { - return nil, e.FormatError("can't unmarshal json payload in raw NetBox API call", err) - } - - // there are no more pages left, return the response we got - if response.Next == "" { - return &response, nil - } - - // there are more pages left, get more responses from there - - // recursive calling of handlePagination to get all following pages - nextResponse, err := nb.handleRawPagination(response.Next) - if err != nil { - return nil, e.FormatError("can't get next response from api", err) - } - - // append all next responses' results to this response's result - response.Results = append(response.Results, nextResponse.Results...) - - // go back up the chain through recursion - return &response, nil -} - -func (nb NetBoxAPI) handlePagination(url string, payload any) error { - response, err := nb.handleRawPagination(url) - if err != nil { - return e.FormatError("can't handle pagination for url "+url, err) - } - - fmt.Println(response.Count) - - // cast response into our payload - if err := resultToOtherStructure(*response, &payload); err != nil { - return e.FormatError("can't parse result to other Structure", err) - } - - // prettify.Print(payload) - return nil - -} - -func resultToOtherStructure(input apiResponse, output any) error { - // get JSON representation of results - c, err := json.Marshal(input.Results) - if err != nil { - return err - } - - // Unmarshal onto specific structure via output - return json.Unmarshal(c, &output) -} - -func (nb NetBoxAPI) rawNetBoxAPICall(url string, method string, data ...any) ([]byte, error) { - // construct complete URL (url already comes with a "/" after the "/api" part) - // url = fmt.Sprintf("https://%s/api%s", nb.URL, url) - - // log.Printf("calling API on url: %s with method %s and data %+v\n", url, method, data) - // create new transport client - - c := &http.Client{} - var req *http.Request - - switch method { - case http.MethodPatch, http.MethodPost, http.MethodPut: - // to patch something we need data, check it exists - if data == nil { - return nil, fmt.Errorf("no data was provided, please provide data to use PATCH") - } - - payload, err := json.Marshal(data) - if err != nil { - return nil, e.FormatError(fmt.Sprintf("can't marshal data %+v for apicall %s", data, url), err) - } - - // construct request - innerRequest, err := http.NewRequest(method, url, bytes.NewBuffer(payload)) - if err != nil { - return nil, e.FormatError(fmt.Sprintf("can't construct new request (method: %s, URL: %s, payload %s)", method, url, payload), err) - } - - // hand over request to outer request - req = innerRequest - - case http.MethodGet: - innerRequest, err := http.NewRequest(method, url, nil) - if err != nil { - return nil, e.FormatError(fmt.Sprintf("can't construct new request (method: %s, URL: %s)", method, url), err) - } - - // hand over request to outer request - req = innerRequest - } - - // set request headers - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Authorization", fmt.Sprintf("Token %s", nb.Token)) - - // call API client with request - resp, err := c.Do(req) - if err != nil { - return nil, e.FormatError("can't get response from "+url, err) - } - defer resp.Body.Close() - - // read body of response - body, err := io.ReadAll(resp.Body) - if err != nil { - return nil, e.FormatError("can't read response body", err) - } - - switch resp.StatusCode { - case 200, 201: - return body, nil - default: - return body, fmt.Errorf("got bad StatusCode %d in response from API, data is:\n\t-> %+v", resp.StatusCode, data) - } -} diff --git a/ipam.go b/ipam.go index 32fc3e0..687487d 100644 --- a/ipam.go +++ b/ipam.go @@ -34,32 +34,31 @@ func (nb NetBoxAPI) GetPrefixes(param ipam.IpamPrefixesListParams) ([]*models.Pr return nil, e.FormatError("can't get prefixes", err) } - // variable to hold all prefixes to return - var prefixesToReturn []*models.Prefix - - // append first page of models - prefixesToReturn = append(prefixesToReturn, prefixes.Payload.Results...) - // check if there are more prefixes on other pages - if prefixes.Payload.Next != nil { - // there are more pages to get - - // calculate new offset - newOffset := *param.Offset + *param.Limit - - // set new offset - param.Offset = &newOffset - - // get prefixes from next page - nextPagePrefixes, err := nb.GetPrefixes(param) - if err != nil { - return nil, e.FormatError("can't get prefixes", err) - } - // append the results from next page to our prefixes to return - prefixesToReturn = append(prefixesToReturn, nextPagePrefixes...) + if prefixes.Payload.Next == nil { + // return the results of the first batch, there are no others + return prefixes.Payload.Results, nil } - return prefixesToReturn, nil + // there are more pages to get + + // calculate new offset + newOffset := *param.Offset + *param.Limit + + // set new offset + param.Offset = &newOffset + + // get prefixes from next page + nextPagePrefixes, err := nb.GetPrefixes(param) + if err != nil { + return nil, e.FormatError("can't get prefixes", err) + } + + // append the results from next page to our prefixes to return + prefixes.Payload.Results = append(prefixes.Payload.Results, nextPagePrefixes...) + + // return all prefixes + return prefixes.Payload.Results, nil } // GetIPAddresses returns IP addresses from the api filtered by the parameter list param @@ -90,20 +89,27 @@ func (nb NetBoxAPI) GetIPAddresses(param ipam.IpamIPAddressesListParams) ([]*mod // check if there are no more prefixes on other pages if addresses.Payload.Next == nil { - // return the results of the first batch, there are no others! + // return the results of the first batch, there are no others return addresses.Payload.Results, nil } - // variable to hold all prefixes to return - var addressesToReturn []*models.IPAddress + // there are more pages to get - if err := nb.handlePagination(addresses.Payload.Next.String(), &addressesToReturn); err != nil { - return nil, e.FormatError("can't handle Pagination", err) + // calculate new offset + newOffset := *param.Offset + *param.Limit + + // set new offset + param.Offset = &newOffset + + // get prefixes from next page + nextPageIPAddresses, err := nb.GetIPAddresses(param) + if err != nil { + return nil, e.FormatError("can't get IP addresses", err) } - // append append first batch to the other batches - addressesToReturn = append(addressesToReturn, addresses.Payload.Results...) + // append the results from next page to our prefixes to return + addresses.Payload.Results = append(addresses.Payload.Results, nextPageIPAddresses...) // return all addresses - return addressesToReturn, nil + return addresses.Payload.Results, nil }