Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VAULT-29412: Preview of new Vault Radar resource. #1092

Merged
merged 12 commits into from
Sep 24, 2024
3 changes: 3 additions & 0 deletions .changelog/1092.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
Add preview of vault_radar_source_github_enterprise resource.
```
46 changes: 46 additions & 0 deletions docs/resources/vault_radar_source_github_enterprise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
page_title: "hcp_vault_radar_source_github_enterprise Resource - terraform-provider-hcp"
subcategory: ""
jasonpilz marked this conversation as resolved.
Show resolved Hide resolved
description: |-
This terraform resource manages a GitHub Enterprise Server data source lifecycle in Vault Radar.
---

# hcp_vault_radar_source_github_enterprise (Resource)

-> **Note:** HCP Vault Radar Terraform resources are in preview.
jasonpilz marked this conversation as resolved.
Show resolved Hide resolved

This terraform resource manages a GitHub Enterprise Server data source lifecycle in Vault Radar.

## Example Usage

```terraform
variable "github_enterprise_token" {
type = string
sensitive = true
}

resource "hcp_vault_radar_source_github_enterprise" "example" {
domain_name = "myserver.acme.com"
github_organization = "my-github-org"
token = var.github_enterprise_token
project_id = "my-project-id"
trentdibacco marked this conversation as resolved.
Show resolved Hide resolved
}
```


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

### Required

- `domain_name` (String) Fully qualified domain name of the server. (Example: myserver.acme.com)
- `github_organization` (String) GitHub organization Vault Radar will monitor. Example: "octocat" for the org https://yourcodeserver.com/octocat
- `token` (String, Sensitive) GitHub personal access token.

### Optional

- `project_id` (String) The ID of the HCP project where Vault Radar is located. If not specified, the project specified in the HCP Provider config block will be used, if configured.

### Read-Only

- `id` (String) The ID of this resource.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
variable "github_enterprise_token" {
type = string
sensitive = true
}

resource "hcp_vault_radar_source_github_enterprise" "example" {
domain_name = "myserver.acme.com"
github_organization = "my-github-org"
token = var.github_enterprise_token
project_id = "my-project-id"
}
83 changes: 44 additions & 39 deletions internal/clients/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ import (
cloud_webhook "github.com/hashicorp/hcp-sdk-go/clients/cloud-webhook/stable/2023-05-31/client"
"github.com/hashicorp/hcp-sdk-go/clients/cloud-webhook/stable/2023-05-31/client/webhook_service"

cloud_vault_radar "github.com/hashicorp/hcp-sdk-go/clients/cloud-vault-radar/preview/2023-05-01/client"
radar_src_registration_service "github.com/hashicorp/hcp-sdk-go/clients/cloud-vault-radar/preview/2023-05-01/client/data_source_registration_service"

hcpConfig "github.com/hashicorp/hcp-sdk-go/config"
sdk "github.com/hashicorp/hcp-sdk-go/httpclient"
)
Expand All @@ -69,25 +72,26 @@ import (
type Client struct {
Config ClientConfig

Billing billing_account_service.ClientService
Boundary boundary_service.ClientService
Consul consul_service.ClientService
IAM iam_service.ClientService
Network network_service.ClientService
Operation operation_service.ClientService
Organization organization_service.ClientService
Packer packer_service.ClientService
PackerV2 packer_service_v2.ClientService
Project project_service.ClientService
ServicePrincipals service_principals_service.ClientService
Groups groups_service.ClientService
Vault vault_service.ClientService
VaultSecrets secret_service.ClientService
VaultSecretsPreview secret_service_preview.ClientService
Waypoint waypoint_service.ClientService
Webhook webhook_service.ClientService
LogService log_service.ClientService
ResourceService resource_service.ClientService
Billing billing_account_service.ClientService
Boundary boundary_service.ClientService
Consul consul_service.ClientService
IAM iam_service.ClientService
Network network_service.ClientService
Operation operation_service.ClientService
Organization organization_service.ClientService
Packer packer_service.ClientService
PackerV2 packer_service_v2.ClientService
Project project_service.ClientService
ServicePrincipals service_principals_service.ClientService
Groups groups_service.ClientService
Vault vault_service.ClientService
VaultSecrets secret_service.ClientService
VaultSecretsPreview secret_service_preview.ClientService
Waypoint waypoint_service.ClientService
Webhook webhook_service.ClientService
LogService log_service.ClientService
ResourceService resource_service.ClientService
RadarSourceRegistrationService radar_src_registration_service.ClientService
}

// ClientConfig specifies configuration for the client that interacts with HCP
Expand Down Expand Up @@ -157,26 +161,27 @@ func NewClient(config ClientConfig) (*Client, error) {
}

client := &Client{
Config: config,
Billing: cloud_billing.New(httpClient, nil).BillingAccountService,
Boundary: cloud_boundary.New(httpClient, nil).BoundaryService,
Consul: cloud_consul.New(httpClient, nil).ConsulService,
IAM: cloud_iam.New(httpClient, nil).IamService,
Network: cloud_network.New(httpClient, nil).NetworkService,
Operation: cloud_operation.New(httpClient, nil).OperationService,
Organization: cloud_resource_manager.New(httpClient, nil).OrganizationService,
Packer: cloud_packer.New(httpClient, nil).PackerService,
PackerV2: cloud_packer_v2.New(httpClient, nil).PackerService,
Project: cloud_resource_manager.New(httpClient, nil).ProjectService,
ServicePrincipals: cloud_iam.New(httpClient, nil).ServicePrincipalsService,
Groups: cloud_iam.New(httpClient, nil).GroupsService,
Vault: cloud_vault.New(httpClient, nil).VaultService,
VaultSecrets: cloud_vault_secrets.New(httpClient, nil).SecretService,
VaultSecretsPreview: cloud_vault_secrets_preview.New(httpClient, nil).SecretService,
Waypoint: cloud_waypoint.New(httpClient, nil).WaypointService,
LogService: cloud_log_service.New(httpClient, nil).LogService,
Webhook: cloud_webhook.New(httpClient, nil).WebhookService,
ResourceService: cloud_resource_manager.New(httpClient, nil).ResourceService,
Config: config,
Billing: cloud_billing.New(httpClient, nil).BillingAccountService,
Boundary: cloud_boundary.New(httpClient, nil).BoundaryService,
Consul: cloud_consul.New(httpClient, nil).ConsulService,
IAM: cloud_iam.New(httpClient, nil).IamService,
Network: cloud_network.New(httpClient, nil).NetworkService,
Operation: cloud_operation.New(httpClient, nil).OperationService,
Organization: cloud_resource_manager.New(httpClient, nil).OrganizationService,
Packer: cloud_packer.New(httpClient, nil).PackerService,
PackerV2: cloud_packer_v2.New(httpClient, nil).PackerService,
Project: cloud_resource_manager.New(httpClient, nil).ProjectService,
ServicePrincipals: cloud_iam.New(httpClient, nil).ServicePrincipalsService,
Groups: cloud_iam.New(httpClient, nil).GroupsService,
Vault: cloud_vault.New(httpClient, nil).VaultService,
VaultSecrets: cloud_vault_secrets.New(httpClient, nil).SecretService,
VaultSecretsPreview: cloud_vault_secrets_preview.New(httpClient, nil).SecretService,
Waypoint: cloud_waypoint.New(httpClient, nil).WaypointService,
LogService: cloud_log_service.New(httpClient, nil).LogService,
Webhook: cloud_webhook.New(httpClient, nil).WebhookService,
ResourceService: cloud_resource_manager.New(httpClient, nil).ResourceService,
RadarSourceRegistrationService: cloud_vault_radar.New(httpClient, nil).DataSourceRegistrationService,
}

return client, nil
Expand Down
119 changes: 119 additions & 0 deletions internal/clients/vault_radar.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package clients

import (
"context"
"errors"
"time"

radar_service "github.com/hashicorp/hcp-sdk-go/clients/cloud-vault-radar/preview/2023-05-01/client/data_source_registration_service"

"github.com/hashicorp/terraform-plugin-log/tflog"
)

func OnboardRadarSource(ctx context.Context, client *Client, projectID string, source radar_service.OnboardDataSourceBody) (*radar_service.OnboardDataSourceOK, error) {
onboardParams := radar_service.NewOnboardDataSourceParams()
onboardParams.Context = ctx
onboardParams.LocationProjectID = projectID
onboardParams.Body = source

onboardResp, err := client.RadarSourceRegistrationService.OnboardDataSource(onboardParams, nil)
if err != nil {
return nil, err
}

return onboardResp, nil
}

func GetRadarSource(ctx context.Context, client *Client, projectID, sourceID string) (*radar_service.GetDataSourceByIDOK, error) {
getParams := radar_service.NewGetDataSourceByIDParams()
getParams.Context = ctx
getParams.ID = sourceID
getParams.LocationProjectID = projectID

getResp, err := client.RadarSourceRegistrationService.GetDataSourceByID(getParams, nil)
if err != nil {
return nil, err
}

return getResp, nil
}

func OffboardRadarSource(ctx context.Context, client *Client, projectID, sourceID string) error {
tflog.SetField(ctx, "radar_source_id", sourceID)

deleteParams := radar_service.NewOffboardDataSourceParams()
deleteParams.Context = ctx
deleteParams.LocationProjectID = projectID
deleteParams.Body = radar_service.OffboardDataSourceBody{
ID: sourceID,
}

tflog.Trace(ctx, "Initiate radar source offboarding.")
if _, err := client.RadarSourceRegistrationService.OffboardDataSource(deleteParams, nil); err != nil {
return err
}

return WaitOnOffboardRadarSource(ctx, client, projectID, sourceID)
}

func WaitOnOffboardRadarSource(ctx context.Context, client *Client, projectID, sourceID string) error {
deletionConfirmation := func() (bool, error) {
tflog.Trace(ctx, "Confirming radar source deletion.")
if _, err := GetRadarSource(ctx, client, projectID, sourceID); err != nil {
if IsResponseCodeNotFound(err) {
// success, resource not found.
tflog.Trace(ctx, "Success, radar source deletion confirmed.")
return true, nil
}

tflog.Error(ctx, "Failed to confirm radar source deletion.")
return false, err
}

// Resource still exists.
return false, nil
}

retry := 10 * time.Second
timeout := 10 * time.Minute
maxConsecutiveErrors := 5
return waitFor(ctx, retry, timeout, maxConsecutiveErrors, deletionConfirmation)
}

// waitFor waits for isDone to return true or retrying every retry duration until timeout.
// Returns an error if isDone errors or timeout expires.
func waitFor(ctx context.Context, retry, timeout time.Duration, maxConsecutiveErrors int, isDone func() (bool, error)) error {
consecutiveErrors := 0

waitCtx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

ticker := time.NewTicker(retry)
defer ticker.Stop()

for {
if done, err := isDone(); err != nil {
// Check for consecutiveErrors and return error if it exceeds the limit.
if consecutiveErrors >= maxConsecutiveErrors {
return errors.New("max consecutive errors reached")
}
consecutiveErrors++
// Don't call continue here, as we want to wait for the next retry duration.
} else if done {
return nil
} else {
// done == false, err == nil
// Reset consecutiveErrors for next retry call to isDone.
consecutiveErrors = 0
}

select {
case <-ticker.C:
// retry duration has passed.
case <-waitCtx.Done():
return errors.New("timeout expired while waiting")
case <-ctx.Done():
return errors.New("context canceled while waiting")
}
}
}
3 changes: 3 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/hashicorp/terraform-provider-hcp/internal/provider/logstreaming"
"github.com/hashicorp/terraform-provider-hcp/internal/provider/packer"
"github.com/hashicorp/terraform-provider-hcp/internal/provider/resourcemanager"
"github.com/hashicorp/terraform-provider-hcp/internal/provider/vaultradar"
"github.com/hashicorp/terraform-provider-hcp/internal/provider/vaultsecrets"
"github.com/hashicorp/terraform-provider-hcp/internal/provider/waypoint"
"github.com/hashicorp/terraform-provider-hcp/internal/provider/webhook"
Expand Down Expand Up @@ -178,6 +179,8 @@ func (p *ProviderFramework) Resources(ctx context.Context) []func() resource.Res
waypoint.NewAddOnResource,
waypoint.NewAddOnDefinitionResource,
waypoint.NewTfcConfigResource,
// Radar
vaultradar.NewSourceGitHubEnterpriseResource,
}, packer.ResourceSchemaBuilders...)
}

Expand Down
Loading