diff --git a/.changelog/1109.txt b/.changelog/1109.txt new file mode 100644 index 000000000..7a9b2e59b --- /dev/null +++ b/.changelog/1109.txt @@ -0,0 +1,3 @@ +```release-note:feature +Add pagination support for vault OpenAppSecrets preview api. +``` diff --git a/internal/clients/vault_secrets_preview.go b/internal/clients/vault_secrets_preview.go index e77e2a7e8..51e297577 100644 --- a/internal/clients/vault_secrets_preview.go +++ b/internal/clients/vault_secrets_preview.go @@ -61,27 +61,34 @@ func OpenVaultSecretsAppSecrets(ctx context.Context, client *Client, loc *shared var secrets *secret_service.OpenAppSecretsOK var err error - for attempt := 0; attempt < retryCount; attempt++ { - secrets, err = client.VaultSecretsPreview.OpenAppSecrets(params, nil) - if err != nil { - var serviceErr *secret_service.OpenAppSecretDefault - ok := errors.As(err, &serviceErr) - if !ok { + var result []*secretmodels.Secrets20231128OpenSecret + + for { + for attempt := 0; attempt < retryCount; attempt++ { + secrets, err = client.VaultSecretsPreview.OpenAppSecrets(params, nil) + if err != nil { + var serviceErr *secret_service.OpenAppSecretDefault + ok := errors.As(err, &serviceErr) + if !ok { + return nil, err + } + if shouldRetryWithSleep(ctx, serviceErr, attempt, []int{http.StatusTooManyRequests}) { + continue + } return nil, err } - if shouldRetryWithSleep(ctx, serviceErr, attempt, []int{http.StatusTooManyRequests}) { - continue - } - return nil, err + break } - break - } - - if secrets == nil { - return nil, errors.New("unable to get secrets") + if secrets == nil { + return nil, errors.New("unable to get secrets") + } + result = append(result, secrets.GetPayload().Secrets...) + pagination := secrets.GetPayload().Pagination + if pagination == nil || pagination.NextPageToken == "" { + return result, nil + } + params.PaginationNextPageToken = &pagination.NextPageToken } - - return secrets.GetPayload().Secrets, nil } func GetRotatingSecretState(ctx context.Context, client *Client, loc *sharedmodels.HashicorpCloudLocationLocation, appName, secretName string) (*secretmodels.Secrets20231128RotatingSecretState, error) { diff --git a/internal/provider/vaultsecrets/data_source_vault_secrets_app_test.go b/internal/provider/vaultsecrets/data_source_vault_secrets_app_test.go index 95a4954b0..3a6ecfaf6 100644 --- a/internal/provider/vaultsecrets/data_source_vault_secrets_app_test.go +++ b/internal/provider/vaultsecrets/data_source_vault_secrets_app_test.go @@ -116,6 +116,46 @@ func TestAcc_dataSourceVaultSecretsApp(t *testing.T) { }) } +func TestAcc_VaultSecretsOpenAppSecretsPagination(t *testing.T) { + testAppName := generateRandomSlug() + dataSourceAddress := "data.hcp_vault_secrets_app.foo" + secretCount := 12 + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create 12 secrets and validate that all are returned and not just the default v2 api page size 10 + { + PreConfig: func() { + createTestApp(t, testAppName) + + for i := 1; i <= secretCount; i++ { + createTestAppSecret(t, testAppName, "secret"+fmt.Sprint(i), "value"+fmt.Sprint(i)) + } + }, + Config: fmt.Sprintf(` + data "hcp_vault_secrets_app" "foo" { + app_name = %q + }`, testAppName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceAddress, "organization_id"), + resource.TestCheckResourceAttrSet(dataSourceAddress, "project_id"), + // default page size for OpenAppSecrets v2 api is 10, validate that all secrets (pages) are retrieved and not just 1st page (10) + resource.TestCheckResourceAttr(dataSourceAddress, "secrets.%", fmt.Sprintf("%v", secretCount)), + ), + }, + }, + CheckDestroy: func(s *terraform.State) error { + for i := 1; i <= secretCount; i++ { + deleteTestAppSecret(t, testAppName, "secret"+fmt.Sprint(i)) + } + deleteTestApp(t, testAppName) + return nil + }, + }) +} + func createTestApp(t *testing.T, appName string) { t.Helper()