generated from hashicorp/terraform-provider-scaffolding
-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add support for json credentials (#271)
- Loading branch information
Showing
6 changed files
with
518 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "boundary_credential_json Resource - terraform-provider-boundary" | ||
subcategory: "" | ||
description: |- | ||
The json credential resource allows you to congiure a credential using a json object. | ||
--- | ||
|
||
# boundary_credential_json (Resource) | ||
|
||
The json credential resource allows you to congiure a credential using a json object. | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
resource "boundary_scope" "org" { | ||
name = "organization_one" | ||
description = "global scope" | ||
scope_id = "global" | ||
auto_create_admin_role = true | ||
auto_create_default_role = true | ||
} | ||
resource "boundary_scope" "project" { | ||
name = "project_one" | ||
description = "My first scope!" | ||
scope_id = boundary_scope.org.id | ||
auto_create_admin_role = true | ||
} | ||
resource "boundary_credential_store_static" "example" { | ||
name = "example_static_credential_store" | ||
description = "My first static credential store!" | ||
scope_id = boundary_scope.project.id | ||
} | ||
resource "boundary_credential_json" "example" { | ||
name = "example_json" | ||
description = "My first json credential!" | ||
credential_store_id = boundary_credential_store_static.example.id | ||
object = file("~/object.json") # change to valid json file | ||
} | ||
``` | ||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `credential_store_id` (String) The credential store in which to save this json credential. | ||
- `object` (String, Sensitive) The object for the this json credential. Either values encoded with the "jsonencode" function, pre-escaped JSON string, or a file | ||
|
||
### Optional | ||
|
||
- `description` (String) The description of this json credential. | ||
- `name` (String) The name of this json credential. Defaults to the resource name. | ||
|
||
### Read-Only | ||
|
||
- `id` (String) The ID of this json credential. | ||
- `object_hmac` (String) The object hmac. | ||
|
||
## Import | ||
|
||
Import is supported using the following syntax: | ||
|
||
```shell | ||
terraform import boundary_credential_json.example_json <my-id> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
terraform import boundary_credential_json.example_json <my-id> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
resource "boundary_scope" "org" { | ||
name = "organization_one" | ||
description = "global scope" | ||
scope_id = "global" | ||
auto_create_admin_role = true | ||
auto_create_default_role = true | ||
} | ||
|
||
resource "boundary_scope" "project" { | ||
name = "project_one" | ||
description = "My first scope!" | ||
scope_id = boundary_scope.org.id | ||
auto_create_admin_role = true | ||
} | ||
|
||
resource "boundary_credential_store_static" "example" { | ||
name = "example_static_credential_store" | ||
description = "My first static credential store!" | ||
scope_id = boundary_scope.project.id | ||
} | ||
|
||
resource "boundary_credential_json" "example" { | ||
name = "example_json" | ||
description = "My first json credential!" | ||
credential_store_id = boundary_credential_store_static.example.id | ||
object = file("~/object.json") # change to valid json file | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
package provider | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"net/http" | ||
|
||
"github.com/hashicorp/boundary/api" | ||
"github.com/hashicorp/boundary/api/credentials" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
) | ||
|
||
const ( | ||
credentialJsonCredentialType = "json" | ||
credentialJsonObjectKey = "object" | ||
credentialJsonObjectHmacKey = "object_hmac" | ||
) | ||
|
||
func resourceCredentialJson() *schema.Resource { | ||
return &schema.Resource{ | ||
Description: "The json credential resource allows you to congiure a credential using a json object.", | ||
|
||
CreateContext: resourceCredentialJsonCreate, | ||
ReadContext: resourceCredentialJsonRead, | ||
UpdateContext: resourceCredentialJsonUpdate, | ||
DeleteContext: resourceCredentialJsonDelete, | ||
Importer: &schema.ResourceImporter{ | ||
StateContext: schema.ImportStatePassthroughContext, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
IDKey: { | ||
Description: "The ID of this json credential.", | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
NameKey: { | ||
Description: "The name of this json credential. Defaults to the resource name.", | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
DescriptionKey: { | ||
Description: "The description of this json credential.", | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
credentialStoreIdKey: { | ||
Description: "The credential store in which to save this json credential.", | ||
Type: schema.TypeString, | ||
ForceNew: true, | ||
Required: true, | ||
}, | ||
credentialJsonObjectKey: { | ||
Description: `The object for the this json credential. Either values encoded with the "jsonencode" function, pre-escaped JSON string, or a file`, | ||
Type: schema.TypeString, | ||
Required: true, | ||
Sensitive: true, | ||
}, | ||
credentialJsonObjectHmacKey: { | ||
Description: "The object hmac.", | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func setFromCredentialJsonResponseMap(d *schema.ResourceData, raw map[string]interface{}, fromRead bool) error { | ||
if err := d.Set(NameKey, raw[NameKey]); err != nil { | ||
return err | ||
} | ||
if err := d.Set(DescriptionKey, raw[DescriptionKey]); err != nil { | ||
return err | ||
} | ||
if err := d.Set(credentialStoreIdKey, raw[credentialStoreIdKey]); err != nil { | ||
return err | ||
} | ||
|
||
if attrsVal, ok := raw["attributes"]; ok { | ||
attrs := attrsVal.(map[string]interface{}) | ||
stateObjectHmac := d.Get(credentialJsonObjectHmacKey) | ||
boundaryObjectHmac := attrs[credentialJsonObjectHmacKey].(string) | ||
if stateObjectHmac.(string) != boundaryObjectHmac && fromRead { | ||
if err := d.Set(credentialJsonObjectKey, "(changed in Boundary)"); err != nil { | ||
return err | ||
} | ||
} | ||
if err := d.Set(credentialJsonObjectHmacKey, boundaryObjectHmac); err != nil { | ||
return nil | ||
} | ||
} | ||
|
||
d.SetId(raw["id"].(string)) | ||
|
||
return nil | ||
} | ||
|
||
func resourceCredentialJsonCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
md := meta.(*metaData) | ||
|
||
var opts []credentials.Option | ||
if v, ok := d.GetOk(NameKey); ok { | ||
opts = append(opts, credentials.WithName(v.(string))) | ||
} | ||
if v, ok := d.GetOk(DescriptionKey); ok { | ||
opts = append(opts, credentials.WithDescription(v.(string))) | ||
} | ||
|
||
if v, ok := d.GetOk(credentialJsonObjectKey); ok { | ||
var jsonObject map[string]interface{} | ||
if err := json.Unmarshal([]byte(v.(string)), &jsonObject); err != nil { | ||
return diag.Errorf("error unmarshaling json: %v", err) | ||
} | ||
opts = append(opts, credentials.WithJsonCredentialObject(jsonObject)) | ||
} | ||
|
||
var credentialStoreId string | ||
retrievedStoreId, ok := d.GetOk(credentialStoreIdKey) | ||
if ok { | ||
credentialStoreId = retrievedStoreId.(string) | ||
} else { | ||
return diag.Errorf("credential store id is unset") | ||
} | ||
|
||
client := credentials.NewClient(md.client) | ||
cred, err := client.Create(ctx, credentialJsonCredentialType, credentialStoreId, opts...) | ||
if err != nil { | ||
return diag.Errorf("error creating credential: %v", err) | ||
} | ||
if cred == nil { | ||
return diag.Errorf("nil credential after create") | ||
} | ||
|
||
if err := setFromCredentialJsonResponseMap(d, cred.GetResponse().Map, false); err != nil { | ||
return diag.Errorf("error generating credential from response map: %v", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceCredentialJsonRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
md := meta.(*metaData) | ||
client := credentials.NewClient(md.client) | ||
|
||
cred, err := client.Read(ctx, d.Id()) | ||
if err != nil { | ||
if apiErr := api.AsServerError(err); apiErr != nil && apiErr.Response().StatusCode() == http.StatusNotFound { | ||
d.SetId("") | ||
return nil | ||
} | ||
return diag.Errorf("error reading credential: %v", err) | ||
} | ||
if cred == nil { | ||
return diag.Errorf("credential nil after read") | ||
} | ||
|
||
if err := setFromCredentialJsonResponseMap(d, cred.GetResponse().Map, true); err != nil { | ||
return diag.Errorf("error generating credential from response map: %v", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceCredentialJsonUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
md := meta.(*metaData) | ||
client := credentials.NewClient(md.client) | ||
|
||
var opts []credentials.Option | ||
if d.HasChange(NameKey) { | ||
opts = append(opts, credentials.DefaultName()) | ||
if v, ok := d.GetOk(NameKey); ok { | ||
opts = append(opts, credentials.WithName(v.(string))) | ||
} | ||
} | ||
|
||
if d.HasChange(DescriptionKey) { | ||
opts = append(opts, credentials.DefaultDescription()) | ||
if v, ok := d.GetOk(DescriptionKey); ok { | ||
opts = append(opts, credentials.WithDescription(v.(string))) | ||
} | ||
} | ||
|
||
if d.HasChange(credentialJsonObjectKey) { | ||
if v, ok := d.GetOk(credentialJsonObjectKey); ok { | ||
var jsonObject map[string]interface{} | ||
if err := json.Unmarshal([]byte(v.(string)), &jsonObject); err != nil { | ||
return diag.Errorf("error unmarshaling json: %v", err) | ||
} | ||
opts = append(opts, credentials.WithJsonCredentialObject(jsonObject)) | ||
} | ||
} | ||
|
||
if len(opts) > 0 { | ||
opts = append(opts, credentials.WithAutomaticVersioning(true)) | ||
credUpdate, err := client.Update(ctx, d.Id(), 0, opts...) | ||
if err != nil { | ||
return diag.Errorf("error updating credential: %v", err) | ||
} | ||
if credUpdate == nil { | ||
return diag.Errorf("credential nil after update") | ||
} | ||
|
||
if err = setFromCredentialJsonResponseMap(d, credUpdate.GetResponse().Map, false); err != nil { | ||
return diag.Errorf("error generating credential from response map: %v", err) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceCredentialJsonDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
md := meta.(*metaData) | ||
client := credentials.NewClient(md.client) | ||
|
||
_, err := client.Delete(ctx, d.Id()) | ||
if err != nil { | ||
return diag.Errorf("error deleting credential: %v", err) | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.