Skip to content

Commit

Permalink
[HCP Vault Secrets] Add support for Postgres integration CRUDL (#189)
Browse files Browse the repository at this point in the history
* Postgres Integration

* changelog
  • Loading branch information
averche authored Nov 18, 2024
1 parent 16f7b40 commit 038205f
Show file tree
Hide file tree
Showing 12 changed files with 987 additions and 30 deletions.
3 changes: 3 additions & 0 deletions .changelog/189.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
vault-secrets: Adds support for creating / updating / reading / deleting Postgres integrations.
```
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/hcl/v2 v2.22.0
github.com/hashicorp/hcp-sdk-go v0.117.0
github.com/hashicorp/hcp-sdk-go v0.121.0
github.com/lithammer/dedent v1.1.0
github.com/manifoldco/promptui v0.9.0
github.com/mitchellh/cli v1.1.5
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mO
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hcl/v2 v2.22.0 h1:hkZ3nCtqeJsDhPRFz5EA9iwcG1hNWGePOTw6oyul12M=
github.com/hashicorp/hcl/v2 v2.22.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
github.com/hashicorp/hcp-sdk-go v0.117.0 h1:7lJpkinpWdsXtejC+X7MdaE/3zhFMweB9Ym3uJ7qFJw=
github.com/hashicorp/hcp-sdk-go v0.117.0/go.mod h1:vQ4fzdL1AmhIAbCw+4zmFe5Hbpajj3NvRWkJoVuxmAk=
github.com/hashicorp/hcp-sdk-go v0.121.0 h1:fDCB0sexSNontS7LLuhF1RJd7eYx1hmFVBFmY4kXU78=
github.com/hashicorp/hcp-sdk-go v0.121.0/go.mod h1:vQ4fzdL1AmhIAbCw+4zmFe5Hbpajj3NvRWkJoVuxmAk=
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
Expand Down
37 changes: 30 additions & 7 deletions internal/commands/vaultsecrets/integrations/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,17 +111,19 @@ type IntegrationConfig struct {
}

var (
TwilioKeys = []string{"account_sid", "api_key_secret", "api_key_sid"}
MongoKeys = []string{"private_key", "public_key"}
AWSKeys = []string{"access_keys", "federated_workload_identity"}
GCPKeys = []string{"service_account_key", "federated_workload_identity"}
TwilioKeys = []string{"account_sid", "api_key_secret", "api_key_sid"}
MongoKeys = []string{"private_key", "public_key"}
AWSKeys = []string{"access_keys", "federated_workload_identity"}
GCPKeys = []string{"service_account_key", "federated_workload_identity"}
PostgresKeys = []string{"connection_string"}
)

var providerToRequiredFields = map[string][]string{
string(Twilio): TwilioKeys,
string(MongoDBAtlas): MongoKeys,
string(AWS): AWSKeys,
string(GCP): GCPKeys,
string(Postgres): PostgresKeys,
}

var awsAuthMethodsToReqKeys = map[string][]string{
Expand Down Expand Up @@ -201,7 +203,6 @@ func createRun(opts *CreateOpts) error {
req.Body.Name = opts.IntegrationName

_, err = opts.PreviewClient.CreateMongoDBAtlasIntegration(req, nil)

if err != nil {
return fmt.Errorf("failed to create MongoDB Atlas integration: %w", err)
}
Expand All @@ -225,7 +226,6 @@ func createRun(opts *CreateOpts) error {
req.Body.Name = opts.IntegrationName

_, err = opts.PreviewClient.CreateAwsIntegration(req, nil)

if err != nil {
return fmt.Errorf("failed to create AWS integration: %w", err)
}
Expand All @@ -249,11 +249,34 @@ func createRun(opts *CreateOpts) error {
req.Body.Name = opts.IntegrationName

_, err = opts.PreviewClient.CreateGcpIntegration(req, nil)

if err != nil {
return fmt.Errorf("failed to create GCP integration: %w", err)
}

case Postgres:
req := preview_secret_service.NewCreatePostgresIntegrationParamsWithContext(opts.Ctx)
req.OrganizationID = opts.Profile.OrganizationID
req.ProjectID = opts.Profile.ProjectID

detailBytes, err := json.Marshal(internalConfig.Details)
if err != nil {
return fmt.Errorf("error marshaling details config: %w", err)
}

var body preview_models.SecretServiceCreatePostgresIntegrationBody
err = body.UnmarshalBinary(detailBytes)
if err != nil {
return fmt.Errorf("error marshaling details config: %w", err)
}

req.Body = &body
req.Body.Name = opts.IntegrationName

_, err = opts.PreviewClient.CreatePostgresIntegration(req, nil)
if err != nil {
return fmt.Errorf("failed to create MongoDB Atlas integration: %w", err)
}

default:
return fmt.Errorf("unsupported integration provider type")
}
Expand Down
25 changes: 14 additions & 11 deletions internal/commands/vaultsecrets/integrations/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,6 @@ func deleteRun(opts *DeleteOpts) error {
return fmt.Errorf("failed to delete integration: %w", err)
}

fmt.Fprintf(opts.IO.Err(), "%s Successfully deleted integration with name %q\n", opts.IO.ColorScheme().SuccessIcon(), opts.IntegrationName)
return nil

case MongoDBAtlas:
_, err := opts.PreviewClient.DeleteMongoDBAtlasIntegration(&preview_secret_service.DeleteMongoDBAtlasIntegrationParams{
Context: opts.Ctx,
Expand All @@ -113,9 +110,6 @@ func deleteRun(opts *DeleteOpts) error {
return fmt.Errorf("failed to delete integration: %w", err)
}

fmt.Fprintf(opts.IO.Err(), "%s Successfully deleted integration with name %q\n", opts.IO.ColorScheme().SuccessIcon(), opts.IntegrationName)
return nil

case AWS:
_, err := opts.PreviewClient.DeleteAwsIntegration(&preview_secret_service.DeleteAwsIntegrationParams{
Context: opts.Ctx,
Expand All @@ -127,9 +121,6 @@ func deleteRun(opts *DeleteOpts) error {
return fmt.Errorf("failed to delete integration: %w", err)
}

fmt.Fprintf(opts.IO.Err(), "%s Successfully deleted integration with name %q\n", opts.IO.ColorScheme().SuccessIcon(), opts.IntegrationName)
return nil

case GCP:
_, err := opts.PreviewClient.DeleteGcpIntegration(&preview_secret_service.DeleteGcpIntegrationParams{
Context: opts.Ctx,
Expand All @@ -141,10 +132,22 @@ func deleteRun(opts *DeleteOpts) error {
return fmt.Errorf("failed to delete integration: %w", err)
}

fmt.Fprintf(opts.IO.Err(), "%s Successfully deleted integration with name %q\n", opts.IO.ColorScheme().SuccessIcon(), opts.IntegrationName)
return nil
case Postgres:
_, err := opts.PreviewClient.DeletePostgresIntegration(&preview_secret_service.DeletePostgresIntegrationParams{
Context: opts.Ctx,
ProjectID: opts.Profile.ProjectID,
OrganizationID: opts.Profile.OrganizationID,
Name: opts.IntegrationName,
}, nil)
if err != nil {
return fmt.Errorf("failed to delete integration: %w", err)
}

default:
return fmt.Errorf("not a valid integration type")
}

fmt.Fprintf(opts.IO.Err(), "%s Successfully deleted integration with name %q\n", opts.IO.ColorScheme().SuccessIcon(), opts.IntegrationName)

return nil
}
59 changes: 55 additions & 4 deletions internal/commands/vaultsecrets/integrations/displayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ func (m *mongodbDisplayer) DefaultFormat() format.Format {
}

func (m *mongodbDisplayer) Payload() any {

if m.previewMongoDBIntegrations != nil {
return m.previewMongoDBIntegrationsPayload()
}
Expand Down Expand Up @@ -143,7 +142,6 @@ func (a *awsDisplayer) DefaultFormat() format.Format {
}

func (a *awsDisplayer) Payload() any {

if a.previewAwsIntegrations != nil {
return a.previewAwsIntegrationsPayload()
}
Expand Down Expand Up @@ -183,7 +181,6 @@ func (a *awsDisplayer) FieldTemplates() []format.Field {
ValueFormat: "{{ .FederatedWorkloadIdentity.RoleArn }}",
},
}...)

} else {
return append(fields, []format.Field{
{
Expand Down Expand Up @@ -214,7 +211,6 @@ func (g *gcpDisplayer) DefaultFormat() format.Format {
}

func (g *gcpDisplayer) Payload() any {

if g.previewGcpIntegrations != nil {
return g.previewGcpIntegrationsPayload()
}
Expand Down Expand Up @@ -319,3 +315,58 @@ func (g *genericDisplayer) FieldTemplates() []format.Field {
},
}
}

type postgresDisplayer struct {
previewPostgresIntegrations []*preview_models.Secrets20231128PostgresIntegration

single bool
}

func newPostgresDisplayer(single bool, integrations ...*preview_models.Secrets20231128PostgresIntegration) *postgresDisplayer {
return &postgresDisplayer{
previewPostgresIntegrations: integrations,
single: single,
}
}

func (m *postgresDisplayer) DefaultFormat() format.Format {
return format.Table
}

func (m *postgresDisplayer) Payload() any {
if m.previewPostgresIntegrations != nil {
return m.previewPostgresIntegrationsPayload()
}

return nil
}

func (m *postgresDisplayer) previewPostgresIntegrationsPayload() any {
if m.single {
if len(m.previewPostgresIntegrations) != 1 {
return nil
}
return m.previewPostgresIntegrations[0]
}
return m.previewPostgresIntegrations
}

func (m *postgresDisplayer) FieldTemplates() []format.Field {
fields := []format.Field{
{
Name: "Integration Name",
ValueFormat: "{{ .Name }}",
},
}

if m.single {
return append(fields, []format.Field{
{
Name: "Connection String",
ValueFormat: "{{ .StaticCredentialDetails.ConnectionString }}",
},
}...)
} else {
return fields
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const (
MongoDBAtlas IntegrationType = "mongodb-atlas"
AWS IntegrationType = "aws"
GCP IntegrationType = "gcp"
Postgres IntegrationType = "postgres"
)

func NewCmdIntegrations(ctx *cmd.Context) *cmd.Command {
Expand Down
33 changes: 31 additions & 2 deletions internal/commands/vaultsecrets/integrations/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func listRun(opts *ListOpts) error {
for {
resp, err := opts.PreviewClient.ListTwilioIntegrations(params, nil)
if err != nil {
return fmt.Errorf("failed to list twilio integrations: %w", err)
return fmt.Errorf("failed to list Twilio integrations: %w", err)
}

integrations = append(integrations, resp.Payload.Integrations...)
Expand All @@ -146,7 +146,7 @@ func listRun(opts *ListOpts) error {
for {
resp, err := opts.PreviewClient.ListMongoDBAtlasIntegrations(params, nil)
if err != nil {
return fmt.Errorf("failed to list mongo integrations: %w", err)
return fmt.Errorf("failed to list MongoDB Atlas integrations: %w", err)
}

integrations = append(integrations, resp.Payload.Integrations...)
Expand All @@ -157,6 +157,7 @@ func listRun(opts *ListOpts) error {
next := resp.Payload.Pagination.NextPageToken
params.PaginationNextPageToken = &next
}

return opts.Output.Display(newMongoDBDisplayer(false, integrations...))

case AWS:
Expand All @@ -182,6 +183,7 @@ func listRun(opts *ListOpts) error {
next := resp.Payload.Pagination.NextPageToken
params.PaginationNextPageToken = &next
}

return opts.Output.Display(newAwsDisplayer(false, false, integrations...))

case GCP:
Expand All @@ -207,8 +209,35 @@ func listRun(opts *ListOpts) error {
next := resp.Payload.Pagination.NextPageToken
params.PaginationNextPageToken = &next
}

return opts.Output.Display(newGcpDisplayer(false, false, integrations...))

case Postgres:
var integrations []*preview_models.Secrets20231128PostgresIntegration

params := &preview_secret_service.ListPostgresIntegrationsParams{
Context: opts.Ctx,
ProjectID: opts.Profile.ProjectID,
OrganizationID: opts.Profile.OrganizationID,
}

for {
resp, err := opts.PreviewClient.ListPostgresIntegrations(params, nil)
if err != nil {
return fmt.Errorf("failed to list Postgres integrations: %w", err)
}

integrations = append(integrations, resp.Payload.Integrations...)
if resp.Payload.Pagination == nil || resp.Payload.Pagination.NextPageToken == "" {
break
}

next := resp.Payload.Pagination.NextPageToken
params.PaginationNextPageToken = &next
}

return opts.Output.Display(newPostgresDisplayer(false, integrations...))

default:
return fmt.Errorf("not a valid integration type")
}
Expand Down
13 changes: 13 additions & 0 deletions internal/commands/vaultsecrets/integrations/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,19 @@ func readRun(opts *ReadOpts) error {

return opts.Output.Display(newGcpDisplayer(true, resp.Payload.Integration.FederatedWorkloadIdentity != nil, resp.Payload.Integration))

case Postgres:
resp, err := opts.PreviewClient.GetPostgresIntegration(&preview_secret_service.GetPostgresIntegrationParams{
Context: opts.Ctx,
ProjectID: opts.Profile.ProjectID,
OrganizationID: opts.Profile.OrganizationID,
Name: opts.IntegrationName,
}, nil)
if err != nil {
return fmt.Errorf("failed to read integration: %w", err)
}

return opts.Output.Display(newPostgresDisplayer(true, resp.Payload.Integration))

default:
return fmt.Errorf("not a valid integration type")
}
Expand Down
26 changes: 23 additions & 3 deletions internal/commands/vaultsecrets/integrations/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ func updateRun(opts *UpdateOpts) error {
req.Body = &mongoDBBody

_, err = opts.PreviewClient.UpdateMongoDBAtlasIntegration(req, nil)

if err != nil {
return fmt.Errorf("failed to update MongoDB Atlas integration: %w", err)
}
Expand All @@ -176,7 +175,6 @@ func updateRun(opts *UpdateOpts) error {
req.Body = &awsBody

_, err = opts.PreviewClient.UpdateAwsIntegration(req, nil)

if err != nil {
return fmt.Errorf("failed to update AWS integration: %w", err)
}
Expand All @@ -200,10 +198,32 @@ func updateRun(opts *UpdateOpts) error {
req.Body = &gcpBody

_, err = opts.PreviewClient.UpdateGcpIntegration(req, nil)

if err != nil {
return fmt.Errorf("failed to update GCP integration: %w", err)
}

case Postgres:
req := preview_secret_service.NewUpdatePostgresIntegrationParamsWithContext(opts.Ctx)
req.OrganizationID = opts.Profile.OrganizationID
req.ProjectID = opts.Profile.ProjectID
req.Name = opts.IntegrationName

var body preview_models.SecretServiceUpdatePostgresIntegrationBody
detailBytes, err := json.Marshal(internalConfig.Details)
if err != nil {
return fmt.Errorf("error marshaling details config: %w", err)
}

err = body.UnmarshalBinary(detailBytes)
if err != nil {
return fmt.Errorf("error marshaling details config: %w", err)
}
req.Body = &body

_, err = opts.PreviewClient.UpdatePostgresIntegration(req, nil)
if err != nil {
return fmt.Errorf("failed to update MongoDB Atlas integration: %w", err)
}
}

fmt.Fprintln(opts.IO.Err())
Expand Down
Loading

0 comments on commit 038205f

Please sign in to comment.