Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/1196.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
Add support for sync resource in HCP Vault Secrets
```
1 change: 1 addition & 0 deletions docs/resources/vault_secrets_app.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ resource "hcp_vault_secrets_app" "example" {

- `description` (String) The Vault Secrets app description
- `project_id` (String) The ID of the HCP project where the HCP Vault Secrets app is located.
- `sync_names` (List of String) List of sync names to associate with this app.

### Read-Only

Expand Down
55 changes: 55 additions & 0 deletions docs/resources/vault_secrets_sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
page_title: "Resource hcp_vault_secrets_sync"
subcategory: "HCP Vault Secrets"
description: |-
The Vault Secrets sync resource manages an integration.
---

# hcp_vault_secrets_sync (Resource)

The Vault Secrets sync resource manages an integration.

## Example Usage

```terraform
# the provider is derived from the integration name
resource "hcp_vault_secrets_sync" "example_aws_sync" {
name = "my-aws-1"
integration_name = "my-integration-1"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `integration_name` (String) The Vault Secrets integration name.
- `name` (String) The Vault Secrets Sync name.

### Optional

- `gitlab_config` (Attributes) Configuration parameters used to determine the sync destination. (see [below for nested schema](#nestedatt--gitlab_config))
- `project_id` (String) HCP project ID that owns the HCP Vault Secrets integration. Inferred from the provider configuration if omitted.

### Read-Only

- `id` (String) Required ID field that is set to the sync name.
- `organization_id` (String) HCP organization ID that owns the HCP Vault Secrets integration.

<a id="nestedatt--gitlab_config"></a>
### Nested Schema for `gitlab_config`

Required:

- `project_id` (String, Sensitive)
- `scope` (String)

## Import

Import is supported using the following syntax:

```shell
# Vault Secrets Integration can be imported by specifying the name of the integration
terraform import hcp_vault_secrets_sync.example my-sync-name
```
2 changes: 2 additions & 0 deletions examples/resources/hcp_vault_secrets_sync/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Vault Secrets Integration can be imported by specifying the name of the integration
terraform import hcp_vault_secrets_sync.example my-sync-name
5 changes: 5 additions & 0 deletions examples/resources/hcp_vault_secrets_sync/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# the provider is derived from the integration name
resource "hcp_vault_secrets_sync" "example_aws_sync" {
name = "my-aws-1"
integration_name = "my-integration-1"
}
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ func (p *ProviderFramework) Resources(ctx context.Context) []func() resource.Res
vaultsecrets.NewVaultSecretsIntegrationResource,
vaultsecrets.NewVaultSecretsDynamicSecretResource,
vaultsecrets.NewVaultSecretsRotatingSecretResource,
vaultsecrets.NewVaultSecretsSyncResource,
// Vault Secrets Deprecated
vaultsecrets.NewVaultSecretsIntegrationAWSResource,
vaultsecrets.NewVaultSecretsIntegrationAzureResource,
Expand Down
18 changes: 17 additions & 1 deletion internal/provider/vaultsecrets/resource_vault_secrets_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import (

"github.com/hashicorp/hcp-sdk-go/clients/cloud-vault-secrets/stable/2023-11-28/client/secret_service"
secretmodels "github.com/hashicorp/hcp-sdk-go/clients/cloud-vault-secrets/stable/2023-11-28/models"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
Expand All @@ -30,6 +32,7 @@ type App struct {
ProjectID types.String `tfsdk:"project_id"`
OrganizationID types.String `tfsdk:"organization_id"`
ResourceName types.String `tfsdk:"resource_name"`
SyncNames types.Set `tfsdk:"sync_names"`
}

var _ resource.Resource = &resourceVaultSecretsApp{}
Expand Down Expand Up @@ -90,7 +93,17 @@ func (r *resourceVaultSecretsApp) Schema(_ context.Context, _ resource.SchemaReq
Computed: true,
Description: "The app's resource name in the format secrets/project/<project ID>/app/<app Name>.",
},
},
"sync_names": schema.ListAttribute{
Description: "List of sync names to associate with this app.",
Optional: true,
ElementType: types.StringType,
PlanModifiers: []planmodifier.List{
listplanmodifier.RequiresReplace(),
},
Validators: []validator.List{
listvalidator.UniqueValues(),
},
}},
}
}

Expand Down Expand Up @@ -120,10 +133,13 @@ func (r *resourceVaultSecretsApp) Create(ctx context.Context, req resource.Creat
return nil, fmt.Errorf("invalid resource type, expected *App, got: %T, this is a bug on the provider", i)
}

syncNames := make([]string, len(app.SyncNames.Elements()))

response, err := r.client.VaultSecrets.CreateApp(&secret_service.CreateAppParams{
Body: &secretmodels.SecretServiceCreateAppBody{
Name: app.AppName.ValueString(),
Description: app.Description.ValueString(),
SyncNames: syncNames,
},
OrganizationID: app.OrganizationID.ValueString(),
ProjectID: app.ProjectID.ValueString(),
Expand Down
61 changes: 50 additions & 11 deletions internal/provider/vaultsecrets/resource_vault_secrets_app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package vaultsecrets_test
import (
"fmt"
"os"
"strings"
"testing"

"github.com/hashicorp/hcp-sdk-go/clients/cloud-vault-secrets/stable/2023-11-28/client/secret_service"
Expand All @@ -17,11 +18,15 @@ import (
)

func TestAccVaultSecretsResourceApp(t *testing.T) {
appName1 := generateRandomSlug()
appName2 := generateRandomSlug()

description1 := "my description 1"
description2 := "my description 2"
var (
integrationName1 = generateRandomSlug()
appName1 = generateRandomSlug()
appName2 = generateRandomSlug()
description1 = "my description 1"
description2 = "my description 2"
syncName = generateRandomSlug()
gitLabToken = checkRequiredEnvVarOrFail(t, "GITLAB_ACCESS_TOKEN")
)

resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories,
Expand All @@ -30,21 +35,50 @@ func TestAccVaultSecretsResourceApp(t *testing.T) {
{
Config: appConfig(appName1, description1),
Check: resource.ComposeTestCheckFunc(
appCheckFunc(appName1, description1)...,
appCheckFunc(appName1, description1, nil)...,
),
},
// Changing an immutable field causes a recreation
{
Config: appConfig(appName2, description1),
Check: resource.ComposeTestCheckFunc(
appCheckFunc(appName2, description1)...,
appCheckFunc(appName2, description1, nil)...,
),
},
// Changing mutable fields causes an update
{
Config: appConfig(appName2, description2),
Check: resource.ComposeTestCheckFunc(
appCheckFunc(appName2, description2)...,
appCheckFunc(appName2, description2, nil)...,
),
},
// Changing the sync_names causes an update
{
Config: fmt.Sprintf(`
resource "hcp_vault_secrets_integration" "acc_test" {
name = %q
capabilities = ["SYNC"]
provider_type = "gitlab"
gitlab_access = {
token = %q
}
}
resource "hcp_vault_secrets_sync" "gitlab_sync" {
name = %q
integration_name = hcp_vault_secrets_integration.acc_test.name
gitlab_config {
scope = "PROJECT"
project_id = "1234"
}
}
resource "hcp_vault_secrets_app" "acc_test_app" {
app_name = %q
description = %q
sync_names = [hcp_vault_secrets_sync.gitlab_sync.name]
}
`, integrationName1, gitLabToken, syncName, appName2, description2),
Check: resource.ComposeTestCheckFunc(
appCheckFunc(appName2, description2, []string{syncName})...,
),
},
// Deleting the app out of band causes a recreation
Expand All @@ -63,7 +97,7 @@ func TestAccVaultSecretsResourceApp(t *testing.T) {
},
Config: appConfig(appName2, description2),
Check: resource.ComposeTestCheckFunc(
appCheckFunc(appName2, description2)...,
appCheckFunc(appName2, description2, nil)...,
),
PlanOnly: true,
ExpectNonEmptyPlan: true,
Expand All @@ -87,7 +121,7 @@ func TestAccVaultSecretsResourceApp(t *testing.T) {
},
Config: appConfig(appName2, description2),
Check: resource.ComposeTestCheckFunc(
appCheckFunc(appName2, description2)...,
appCheckFunc(appName2, description2, nil)...,
),
ResourceName: "hcp_vault_secrets_app.acc_test_app",
ImportStateId: appName2,
Expand All @@ -114,14 +148,19 @@ func appConfig(appName, description string) string {
}`, appName, description)
}

func appCheckFunc(appName, description string) []resource.TestCheckFunc {
func appCheckFunc(appName, description string, syncNames []string) []resource.TestCheckFunc {
formattedSyncs := ""
if len(syncNames) > 0 {
formattedSyncs = fmt.Sprintf("[%s]", strings.Join(syncNames, ","))
}
return []resource.TestCheckFunc{
resource.TestCheckResourceAttrSet("hcp_vault_secrets_app.acc_test_app", "organization_id"),
resource.TestCheckResourceAttrSet("hcp_vault_secrets_app.acc_test_app", "id"),
resource.TestCheckResourceAttrSet("hcp_vault_secrets_app.acc_test_app", "resource_name"),
resource.TestCheckResourceAttr("hcp_vault_secrets_app.acc_test_app", "project_id", os.Getenv("HCP_PROJECT_ID")),
resource.TestCheckResourceAttr("hcp_vault_secrets_app.acc_test_app", "app_name", appName),
resource.TestCheckResourceAttr("hcp_vault_secrets_app.acc_test_app", "description", description),
resource.TestCheckResourceAttr("hcp_vault_secrets_app.acc_test_app", "sync_names", formattedSyncs),
}
}

Expand Down
Loading