diff --git a/pkg/dbt_cloud/paginate.go b/pkg/dbt_cloud/paginate.go index e0fed97..fedf1f6 100644 --- a/pkg/dbt_cloud/paginate.go +++ b/pkg/dbt_cloud/paginate.go @@ -15,6 +15,11 @@ type Response struct { Extra Extra `json:"extra"` } +type RawResponse struct { + Data []json.RawMessage `json:"data"` + Extra Extra `json:"extra"` +} + type Extra struct { Pagination Pagination `json:"pagination"` } @@ -40,19 +45,19 @@ func (c *Client) GetEndpoint(url string) ([]byte, error) { return resp, err } -func (c *Client) GetData(url string) []any { +func (c *Client) GetRawData(url string) ([]json.RawMessage, error) { // get the first page jsonPayload, err := c.GetEndpoint(url) if err != nil { - log.Fatal(err) + return nil, err } - var response Response + var response RawResponse err = json.Unmarshal(jsonPayload, &response) if err != nil { - log.Fatal(err) + return nil, err } allResponses := response.Data @@ -71,13 +76,13 @@ func (c *Client) GetData(url string) []any { jsonPayload, err := c.GetEndpoint(newURL) if err != nil { - log.Fatal(err) + return nil, err } - var response Response + var response RawResponse err = json.Unmarshal(jsonPayload, &response) if err != nil { - log.Fatal(err) + return nil, err } if response.Extra.Pagination.Count == 0 { @@ -90,7 +95,23 @@ func (c *Client) GetData(url string) []any { allResponses = append(allResponses, response.Data...) } - return allResponses + return allResponses, nil +} + +func (c *Client) GetData(url string) []any { + rawData, err := c.GetRawData(url) + if err != nil { + log.Fatal(err) + } + + allData := make([]any, len(rawData)) + for i, data := range rawData { + err := json.Unmarshal(data, &allData[i]) + if err != nil { + log.Fatal(err) + } + } + return allData } func (c *Client) GetAllGroupIDsByName(groupName string) []int { diff --git a/pkg/dbt_cloud/service_token.go b/pkg/dbt_cloud/service_token.go index b77ee9c..9ffa954 100644 --- a/pkg/dbt_cloud/service_token.go +++ b/pkg/dbt_cloud/service_token.go @@ -45,23 +45,22 @@ type ServiceTokenPermissionListResponse struct { } func (c *Client) GetServiceTokenPermissions(serviceTokenID int) (*[]ServiceTokenPermission, error) { - req, err := http.NewRequest("GET", fmt.Sprintf("%s/v3/accounts/%s/service-tokens/%s/permissions/", c.HostURL, strconv.Itoa(c.AccountID), strconv.Itoa(serviceTokenID)), nil) - if err != nil { - return nil, err - } - body, err := c.doRequest(req) + allServiceTokenPermissionsRaw, err := c.GetRawData(fmt.Sprintf("%s/v3/accounts/%s/service-tokens/%s/permissions/", c.HostURL, strconv.Itoa(c.AccountID), strconv.Itoa(serviceTokenID))) if err != nil { return nil, err } - serviceTokenPermissionListResponse := ServiceTokenPermissionListResponse{} - err = json.Unmarshal(body, &serviceTokenPermissionListResponse) - if err != nil { - return nil, err + allPermissions := make([]ServiceTokenPermission, len(allServiceTokenPermissionsRaw)) + + for i, permission := range allServiceTokenPermissionsRaw { + err := json.Unmarshal(permission, &allPermissions[i]) + if err != nil { + return nil, err + } } - return &serviceTokenPermissionListResponse.Data, nil + return &allPermissions, nil } func (c *Client) GetServiceToken(serviceTokenID int) (*ServiceToken, error) { @@ -165,18 +164,12 @@ func (c *Client) UpdateServiceTokenPermissions(serviceTokenID int, serviceTokenP return nil, err } - body, err := c.doRequest(req) - if err != nil { - return nil, err - } - - serviceTokenPermissionResponse := ServiceTokenPermissionListResponse{} - err = json.Unmarshal(body, &serviceTokenPermissionResponse) + _, err = c.doRequest(req) if err != nil { return nil, err } - return &serviceTokenPermissionResponse.Data, nil + return c.GetServiceTokenPermissions(serviceTokenID) } func (c *Client) DeleteServiceToken(serviceTokenID int) (string, error) { diff --git a/pkg/framework/objects/service_token/gh_280_acc_test.tf.tmpl b/pkg/framework/objects/service_token/gh_280_acc_test.tf.tmpl new file mode 100644 index 0000000..79b352d --- /dev/null +++ b/pkg/framework/objects/service_token/gh_280_acc_test.tf.tmpl @@ -0,0 +1,29 @@ +{{ range .Projects }} +resource "dbtcloud_project" "{{ . }}" { + name = "{{ . }}" +} +{{ end }} + +resource "dbtcloud_service_token" "token" { + name = "issue280" + + {{ range .Projects}} + service_token_permissions { + permission_set = "developer" + all_projects = false + project_id = dbtcloud_project.{{ . }}.id + } + + service_token_permissions { + permission_set = "git_admin" + all_projects = false + project_id = dbtcloud_project.{{ . }}.id + } + + service_token_permissions { + permission_set = "job_admin" + all_projects = false + project_id = dbtcloud_project.{{ . }}.id + } + {{ end }} +} \ No newline at end of file diff --git a/pkg/framework/objects/service_token/resource_acceptance_test.go b/pkg/framework/objects/service_token/resource_acceptance_test.go index 6134db1..9ce638f 100644 --- a/pkg/framework/objects/service_token/resource_acceptance_test.go +++ b/pkg/framework/objects/service_token/resource_acceptance_test.go @@ -1,10 +1,12 @@ package service_token_test import ( + "bytes" "fmt" "regexp" "strconv" "testing" + "text/template" "github.com/dbt-labs/terraform-provider-dbtcloud/pkg/framework/acctest_helper" "github.com/hashicorp/terraform-plugin-testing/helper/acctest" @@ -253,3 +255,36 @@ func testAccCheckDbtCloudServiceTokenDestroy(s *terraform.State) error { return nil } + +func TestServiceTokenPagination_GH_280(t *testing.T) { + + var projects []string + + for i := 1; i <= 40; i++ { + projects = append(projects, fmt.Sprintf("gh_280_test_project%d", i)) + } + + data := struct { + Projects []string + }{ + Projects: projects, + } + + // Parse and execute the template + var output bytes.Buffer + err := template.Must(template.ParseFiles("gh_280_acc_test.tf.tmpl")).Execute(&output, data) + if err != nil { + panic(err) + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest_helper.TestAccPreCheck(t) }, + ProtoV6ProviderFactories: acctest_helper.TestAccProtoV6ProviderFactories, + CheckDestroy: testAccCheckDbtCloudServiceTokenDestroy, + Steps: []resource.TestStep{ + { + Config: output.String(), + }, + }, + }) +}