-
Notifications
You must be signed in to change notification settings - Fork 9.6k
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
[WIP] aws_snapshot_create_volume_permission #9891
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/ec2" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
) | ||
|
||
func resourceAwsSnapshotCreateVolumePermission() *schema.Resource { | ||
return &schema.Resource{ | ||
Exists: resourceAwsSnapshotCreateVolumePermissionExists, | ||
Create: resourceAwsSnapshotCreateVolumePermissionCreate, | ||
Read: resourceAwsSnapshotCreateVolumePermissionRead, | ||
Delete: resourceAwsSnapshotCreateVolumePermissionDelete, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"snapshot_id": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"account_id": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceAwsSnapshotCreateVolumePermissionExists(d *schema.ResourceData, meta interface{}) (bool, error) { | ||
conn := meta.(*AWSClient).ec2conn | ||
|
||
snapshot_id := d.Get("snapshot_id").(string) | ||
account_id := d.Get("account_id").(string) | ||
return hasCreateVolumePermission(conn, snapshot_id, account_id) | ||
} | ||
|
||
func resourceAwsSnapshotCreateVolumePermissionCreate(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).ec2conn | ||
|
||
snapshot_id := d.Get("snapshot_id").(string) | ||
account_id := d.Get("account_id").(string) | ||
|
||
_, err := conn.ModifySnapshotAttribute(&ec2.ModifySnapshotAttributeInput{ | ||
SnapshotId: aws.String(snapshot_id), | ||
Attribute: aws.String("createVolumePermission"), | ||
CreateVolumePermission: &ec2.CreateVolumePermissionModifications{ | ||
Add: []*ec2.CreateVolumePermission{ | ||
&ec2.CreateVolumePermission{UserId: aws.String(account_id)}, | ||
}, | ||
}, | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("Error adding snapshot createVolumePermission: %s", err) | ||
} | ||
|
||
d.SetId(fmt.Sprintf("%s-%s", snapshot_id, account_id)) | ||
|
||
// Wait for the account to appear in the permission list | ||
stateConf := &resource.StateChangeConf{ | ||
Pending: []string{"denied"}, | ||
Target: []string{"granted"}, | ||
Refresh: resourceAwsSnapshotCreateVolumePermissionStateRefreshFunc(conn, snapshot_id, account_id), | ||
Timeout: 5 * time.Minute, | ||
Delay: 10 * time.Second, | ||
MinTimeout: 10 * time.Second, | ||
} | ||
if _, err := stateConf.WaitForState(); err != nil { | ||
return fmt.Errorf( | ||
"Error waiting for snapshot createVolumePermission (%s) to be added: %s", | ||
d.Id(), err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceAwsSnapshotCreateVolumePermissionRead(d *schema.ResourceData, meta interface{}) error { | ||
return nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah, just noticed you implemented the |
||
} | ||
|
||
func resourceAwsSnapshotCreateVolumePermissionDelete(d *schema.ResourceData, meta interface{}) error { | ||
conn := meta.(*AWSClient).ec2conn | ||
|
||
snapshot_id := d.Get("snapshot_id").(string) | ||
account_id := d.Get("account_id").(string) | ||
|
||
_, err := conn.ModifySnapshotAttribute(&ec2.ModifySnapshotAttributeInput{ | ||
SnapshotId: aws.String(snapshot_id), | ||
Attribute: aws.String("createVolumePermission"), | ||
CreateVolumePermission: &ec2.CreateVolumePermissionModifications{ | ||
Remove: []*ec2.CreateVolumePermission{ | ||
&ec2.CreateVolumePermission{UserId: aws.String(account_id)}, | ||
}, | ||
}, | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("Error removing snapshot createVolumePermission: %s", err) | ||
} | ||
|
||
// Wait for the account to disappear from the permission list | ||
stateConf := &resource.StateChangeConf{ | ||
Pending: []string{"granted"}, | ||
Target: []string{"denied"}, | ||
Refresh: resourceAwsSnapshotCreateVolumePermissionStateRefreshFunc(conn, snapshot_id, account_id), | ||
Timeout: 5 * time.Minute, | ||
Delay: 10 * time.Second, | ||
MinTimeout: 10 * time.Second, | ||
} | ||
if _, err := stateConf.WaitForState(); err != nil { | ||
return fmt.Errorf( | ||
"Error waiting for snapshot createVolumePermission (%s) to be removed: %s", | ||
d.Id(), err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func hasCreateVolumePermission(conn *ec2.EC2, snapshot_id string, account_id string) (bool, error) { | ||
_, state, err := resourceAwsSnapshotCreateVolumePermissionStateRefreshFunc(conn, snapshot_id, account_id)() | ||
if err != nil { | ||
return false, err | ||
} | ||
if state == "granted" { | ||
return true, nil | ||
} else { | ||
return false, nil | ||
} | ||
} | ||
|
||
func resourceAwsSnapshotCreateVolumePermissionStateRefreshFunc(conn *ec2.EC2, snapshot_id string, account_id string) resource.StateRefreshFunc { | ||
return func() (interface{}, string, error) { | ||
attrs, err := conn.DescribeSnapshotAttribute(&ec2.DescribeSnapshotAttributeInput{ | ||
SnapshotId: aws.String(snapshot_id), | ||
Attribute: aws.String("createVolumePermission"), | ||
}) | ||
if err != nil { | ||
return nil, "", fmt.Errorf("Error refreshing snapshot createVolumePermission state: %s", err) | ||
} | ||
|
||
for _, vp := range attrs.CreateVolumePermissions { | ||
if *vp.UserId == account_id { | ||
return attrs, "granted", nil | ||
} | ||
} | ||
return attrs, "denied", nil | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func TestAccAWSSnapshotCreateVolumePermission_Basic(t *testing.T) { | ||
snapshot_id := "" | ||
account_id := os.Getenv("AWS_ACCOUNT_ID") | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { | ||
testAccPreCheck(t) | ||
if os.Getenv("AWS_ACCOUNT_ID") == "" { | ||
t.Fatal("AWS_ACCOUNT_ID must be set") | ||
} | ||
}, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
// Scaffold everything | ||
resource.TestStep{ | ||
Config: testAccAWSSnapshotCreateVolumePermissionConfig(account_id, true), | ||
Check: resource.ComposeTestCheckFunc( | ||
testCheckResourceGetAttr("aws_ami_copy.test", "block_device_mappings.0.ebs.snapshot_id", &snapshot_id), | ||
testAccAWSSnapshotCreateVolumePermissionExists(account_id, &snapshot_id), | ||
), | ||
}, | ||
// Drop just create volume permission to test destruction | ||
resource.TestStep{ | ||
Config: testAccAWSSnapshotCreateVolumePermissionConfig(account_id, false), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccAWSSnapshotCreateVolumePermissionDestroyed(account_id, &snapshot_id), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccAWSSnapshotCreateVolumePermissionExists(account_id string, snapshot_id *string) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
conn := testAccProvider.Meta().(*AWSClient).ec2conn | ||
if has, err := hasCreateVolumePermission(conn, *snapshot_id, account_id); err != nil { | ||
return err | ||
} else if !has { | ||
return fmt.Errorf("create volume permission does not exist for '%s' on '%s'", account_id, *snapshot_id) | ||
} | ||
return nil | ||
} | ||
} | ||
|
||
func testAccAWSSnapshotCreateVolumePermissionDestroyed(account_id string, snapshot_id *string) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
conn := testAccProvider.Meta().(*AWSClient).ec2conn | ||
if has, err := hasCreateVolumePermission(conn, *snapshot_id, account_id); err != nil { | ||
return err | ||
} else if has { | ||
return fmt.Errorf("create volume permission still exists for '%s' on '%s'", account_id, *snapshot_id) | ||
} | ||
return nil | ||
} | ||
} | ||
|
||
func testAccAWSSnapshotCreateVolumePermissionConfig(account_id string, includeCreateVolumePermission bool) string { | ||
base := ` | ||
resource "aws_ami_copy" "test" { | ||
name = "create-volume-permission-test" | ||
description = "Create Volume Permission Test Copy" | ||
source_ami_id = "ami-7172b611" | ||
source_ami_region = "us-west-2" | ||
} | ||
` | ||
|
||
if !includeCreateVolumePermission { | ||
return base | ||
} | ||
|
||
return base + fmt.Sprintf(` | ||
resource "aws_snapshot_create_volume_permission" "self-test" { | ||
snapshot_id = "${lookup(lookup(element(aws_ami_copy.test.block_device_mappings, 0), "ebs"), "snapshot_id")}" | ||
account_id = "%s" | ||
} | ||
`, account_id) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we should have this as
account_ids
and support a set of IDs, instead of a single 1:1 relationship?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about that a bit. I agree that it would be nice to supply multiple IDs at once, but I opted to keep this similar to the aws_ami_launch_permission resource. I don't mind changing it if you prefer.