mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-18 04:32:59 -06:00
85ec09111b
This commit adds a new callback, DiffSuppressFunc, to the schema.Schema structure. If set for a given schema, a callback to the user-supplied function will be made for each attribute for which the default type-based diff mechanism produces an attribute diff. Returning `true` from the callback will suppress the diff (i.e. pretend there was no diff), and returning false will retain it as part of the plan. There are a number of motivating examples for this - one of which is included as an example: 1. On SSH public keys, trailing whitespace does not matter in many cases - and in some cases it is added by provider APIs. For digitalocean_ssh_key resources we previously had a StateFunc that trimmed the whitespace - we now have a DiffSuppressFunc which verifies whether the trimmed strings are equivalent. 2. IAM policy equivalence for AWS. A good proportion of AWS issues relate to IAM policies which have been "normalized" (used loosely) by the IAM API endpoints. This can make the JSON strings differ from those generated by iam_policy_document resources or template files, even though the semantics are the same (for example, reordering of `bucket-prefix/` and `bucket-prefix/*` in an S3 bucket policy. DiffSupressFunc can be used to test for semantic equivalence rather than pure text equivalence, but without having to deal with the complexity associated with a full "provider-land" diff implementation without helper/schema.
143 lines
3.2 KiB
Go
143 lines
3.2 KiB
Go
package digitalocean
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/digitalocean/godo"
|
|
"github.com/hashicorp/terraform/helper/schema"
|
|
)
|
|
|
|
func resourceDigitalOceanSSHKey() *schema.Resource {
|
|
return &schema.Resource{
|
|
Create: resourceDigitalOceanSSHKeyCreate,
|
|
Read: resourceDigitalOceanSSHKeyRead,
|
|
Update: resourceDigitalOceanSSHKeyUpdate,
|
|
Delete: resourceDigitalOceanSSHKeyDelete,
|
|
Importer: &schema.ResourceImporter{
|
|
State: schema.ImportStatePassthrough,
|
|
},
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
"id": {
|
|
Type: schema.TypeString,
|
|
Computed: true,
|
|
},
|
|
|
|
"name": {
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"public_key": {
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
ForceNew: true,
|
|
DiffSuppressFunc: resourceDigitalOceanSSHKeyPublicKeyDiffSuppress,
|
|
},
|
|
|
|
"fingerprint": {
|
|
Type: schema.TypeString,
|
|
Computed: true,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func resourceDigitalOceanSSHKeyPublicKeyDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
|
|
return strings.TrimSpace(old) == strings.TrimSpace(new)
|
|
}
|
|
|
|
func resourceDigitalOceanSSHKeyCreate(d *schema.ResourceData, meta interface{}) error {
|
|
client := meta.(*godo.Client)
|
|
|
|
// Build up our creation options
|
|
opts := &godo.KeyCreateRequest{
|
|
Name: d.Get("name").(string),
|
|
PublicKey: d.Get("public_key").(string),
|
|
}
|
|
|
|
log.Printf("[DEBUG] SSH Key create configuration: %#v", opts)
|
|
key, _, err := client.Keys.Create(opts)
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating SSH Key: %s", err)
|
|
}
|
|
|
|
d.SetId(strconv.Itoa(key.ID))
|
|
log.Printf("[INFO] SSH Key: %d", key.ID)
|
|
|
|
return resourceDigitalOceanSSHKeyRead(d, meta)
|
|
}
|
|
|
|
func resourceDigitalOceanSSHKeyRead(d *schema.ResourceData, meta interface{}) error {
|
|
client := meta.(*godo.Client)
|
|
|
|
id, err := strconv.Atoi(d.Id())
|
|
if err != nil {
|
|
return fmt.Errorf("invalid SSH key id: %v", err)
|
|
}
|
|
|
|
key, resp, err := client.Keys.GetByID(id)
|
|
if err != nil {
|
|
// If the key is somehow already destroyed, mark as
|
|
// successfully gone
|
|
if resp != nil && resp.StatusCode == 404 {
|
|
d.SetId("")
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("Error retrieving SSH key: %s", err)
|
|
}
|
|
|
|
d.Set("name", key.Name)
|
|
d.Set("fingerprint", key.Fingerprint)
|
|
d.Set("public_key", key.PublicKey)
|
|
|
|
return nil
|
|
}
|
|
|
|
func resourceDigitalOceanSSHKeyUpdate(d *schema.ResourceData, meta interface{}) error {
|
|
client := meta.(*godo.Client)
|
|
|
|
id, err := strconv.Atoi(d.Id())
|
|
if err != nil {
|
|
return fmt.Errorf("invalid SSH key id: %v", err)
|
|
}
|
|
|
|
var newName string
|
|
if v, ok := d.GetOk("name"); ok {
|
|
newName = v.(string)
|
|
}
|
|
|
|
log.Printf("[DEBUG] SSH key update name: %#v", newName)
|
|
opts := &godo.KeyUpdateRequest{
|
|
Name: newName,
|
|
}
|
|
_, _, err = client.Keys.UpdateByID(id, opts)
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to update SSH key: %s", err)
|
|
}
|
|
|
|
return resourceDigitalOceanSSHKeyRead(d, meta)
|
|
}
|
|
|
|
func resourceDigitalOceanSSHKeyDelete(d *schema.ResourceData, meta interface{}) error {
|
|
client := meta.(*godo.Client)
|
|
|
|
id, err := strconv.Atoi(d.Id())
|
|
if err != nil {
|
|
return fmt.Errorf("invalid SSH key id: %v", err)
|
|
}
|
|
|
|
log.Printf("[INFO] Deleting SSH key: %d", id)
|
|
_, err = client.Keys.DeleteByID(id)
|
|
if err != nil {
|
|
return fmt.Errorf("Error deleting SSH key: %s", err)
|
|
}
|
|
|
|
d.SetId("")
|
|
return nil
|
|
}
|