providers/aws: Opsworks permission resource (#6304)

* add opsworks permission resource

* add docs

* remove permission from state if the permission object could not be found

* remove nil validate function. validation is done in schema.Resource.

* add id to the list of exported values

* renge over permission to check that we have found got the correct one

* removed comment

* removed set id

* fix unknown region us-east-1c

* add user_profile resource

* add docs

* add default value
This commit is contained in:
Jan Schumann 2016-07-21 01:29:33 +02:00 committed by Paul Stack
parent 28d10d6eb5
commit ecb4b5aada
8 changed files with 448 additions and 3 deletions

View File

@ -234,6 +234,8 @@ func Provider() terraform.ResourceProvider {
"aws_opsworks_ganglia_layer": resourceAwsOpsworksGangliaLayer(), "aws_opsworks_ganglia_layer": resourceAwsOpsworksGangliaLayer(),
"aws_opsworks_custom_layer": resourceAwsOpsworksCustomLayer(), "aws_opsworks_custom_layer": resourceAwsOpsworksCustomLayer(),
"aws_opsworks_instance": resourceAwsOpsworksInstance(), "aws_opsworks_instance": resourceAwsOpsworksInstance(),
"aws_opsworks_user_profile": resourceAwsOpsworksUserProfile(),
"aws_opsworks_permission": resourceAwsOpsworksPermission(),
"aws_placement_group": resourceAwsPlacementGroup(), "aws_placement_group": resourceAwsPlacementGroup(),
"aws_proxy_protocol_policy": resourceAwsProxyProtocolPolicy(), "aws_proxy_protocol_policy": resourceAwsProxyProtocolPolicy(),
"aws_rds_cluster": resourceAwsRDSCluster(), "aws_rds_cluster": resourceAwsRDSCluster(),

View File

@ -0,0 +1,155 @@
package aws
import (
"fmt"
"log"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/opsworks"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceAwsOpsworksPermission() *schema.Resource {
return &schema.Resource{
Create: resourceAwsOpsworksPermissionCreate,
Update: resourceAwsOpsworksPermissionCreate,
Delete: resourceAwsOpsworksPermissionDelete,
Read: resourceAwsOpsworksPermissionRead,
Schema: map[string]*schema.Schema{
"id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"allow_ssh": &schema.Schema{
Type: schema.TypeBool,
Computed: true,
Optional: true,
},
"allow_sudo": &schema.Schema{
Type: schema.TypeBool,
Computed: true,
Optional: true,
},
"user_arn": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
// one of deny, show, deploy, manage, iam_only
"level": &schema.Schema{
Type: schema.TypeString,
Computed: true,
Optional: true,
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
expected := [5]string{"deny", "show", "deploy", "manage", "iam_only"}
found := false
for _, b := range expected {
if b == value {
found = true
}
}
if !found {
errors = append(errors, fmt.Errorf(
"%q has to be one of [deny, show, deploy, manage, iam_only]", k))
}
return
},
},
"stack_id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
Optional: true,
},
},
}
}
func resourceAwsOpsworksPermissionDelete(d *schema.ResourceData, meta interface{}) error {
return nil
}
func resourceAwsOpsworksPermissionRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*AWSClient).opsworksconn
req := &opsworks.DescribePermissionsInput{
IamUserArn: aws.String(d.Get("user_arn").(string)),
StackId: aws.String(d.Get("stack_id").(string)),
}
log.Printf("[DEBUG] Reading OpsWorks prermissions for: %s on stack: %s", d.Get("user_arn"), d.Get("stack_id"))
resp, err := client.DescribePermissions(req)
if err != nil {
if awserr, ok := err.(awserr.Error); ok {
if awserr.Code() == "ResourceNotFoundException" {
log.Printf("[INFO] Permission not found")
d.SetId("")
return nil
}
}
return err
}
found := false
id := ""
for _, permission := range resp.Permissions {
id = *permission.IamUserArn + *permission.StackId
if d.Get("user_arn").(string)+d.Get("stack_id").(string) == id {
found = true
d.SetId(id)
d.Set("id", id)
d.Set("allow_ssh", permission.AllowSudo)
d.Set("allow_sodo", permission.AllowSudo)
d.Set("user_arn", permission.IamUserArn)
d.Set("stack_id", permission.StackId)
}
}
if false == found {
d.SetId("")
log.Printf("[INFO] The correct permission could not be found for: %s on stack: %s", d.Get("user_arn"), d.Get("stack_id"))
}
return nil
}
func resourceAwsOpsworksPermissionCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*AWSClient).opsworksconn
req := &opsworks.SetPermissionInput{
AllowSudo: aws.Bool(d.Get("allow_sudo").(bool)),
AllowSsh: aws.Bool(d.Get("allow_ssh").(bool)),
IamUserArn: aws.String(d.Get("user_arn").(string)),
StackId: aws.String(d.Get("stack_id").(string)),
}
var resp *opsworks.SetPermissionOutput
err := resource.Retry(2*time.Minute, func() *resource.RetryError {
var cerr error
resp, cerr = client.SetPermission(req)
if cerr != nil {
log.Printf("[INFO] client error")
if opserr, ok := cerr.(awserr.Error); ok {
// XXX: handle errors
log.Printf("[ERROR] OpsWorks error: %s message: %s", opserr.Code(), opserr.Message())
return resource.RetryableError(cerr)
}
return resource.NonRetryableError(cerr)
}
return nil
})
if err != nil {
return err
}
return resourceAwsOpsworksPermissionRead(d, meta)
}

View File

@ -0,0 +1,41 @@
package aws
import (
"testing"
"github.com/hashicorp/terraform/helper/resource"
)
func TestAccAWSOpsworksPermission(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAwsOpsworksPermissionCreate,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"aws_opsworks_permission.tf-acc-perm", "allow_ssh", "true",
),
resource.TestCheckResourceAttr(
"aws_opsworks_permission.tf-acc-perm", "allow_sudo", "true",
),
resource.TestCheckResourceAttr(
"aws_opsworks_permission.tf-acc-perm", "level", "iam_only",
),
),
},
},
})
}
var testAccAwsOpsworksPermissionCreate = testAccAwsOpsworksUserProfileCreate + `
resource "aws_opsworks_permission" "tf-acc-perm" {
stack_id = "${aws_opsworks_stack.tf-acc.id}"
allow_ssh = true
allow_sudo = true
user_arn = "${aws_opsworks_user_profile.user.user_arn}"
level = "iam_only"
}
`

View File

@ -26,7 +26,7 @@ func TestAccAWSOpsworksStackNoVpc(t *testing.T) {
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ resource.TestStep{
Config: testAccAwsOpsworksStackConfigNoVpcCreate(stackName), Config: testAccAwsOpsworksStackConfigNoVpcCreate(stackName),
Check: testAccAwsOpsworksStackCheckResourceAttrsCreate("us-east-1c", stackName), Check: testAccAwsOpsworksStackCheckResourceAttrsCreate("us-east-1a", stackName),
}, },
// resource.TestStep{ // resource.TestStep{
// Config: testAccAWSOpsworksStackConfigNoVpcUpdate(stackName), // Config: testAccAWSOpsworksStackConfigNoVpcUpdate(stackName),
@ -236,7 +236,7 @@ resource "aws_opsworks_stack" "tf-acc" {
region = "us-east-1" region = "us-east-1"
service_role_arn = "${aws_iam_role.opsworks_service.arn}" service_role_arn = "${aws_iam_role.opsworks_service.arn}"
default_instance_profile_arn = "${aws_iam_instance_profile.opsworks_instance.arn}" default_instance_profile_arn = "${aws_iam_instance_profile.opsworks_instance.arn}"
default_availability_zone = "us-east-1c" default_availability_zone = "us-east-1a"
default_os = "Amazon Linux 2014.09" default_os = "Amazon Linux 2014.09"
default_root_device_type = "ebs" default_root_device_type = "ebs"
custom_json = "{\"key\": \"value\"}" custom_json = "{\"key\": \"value\"}"
@ -317,7 +317,7 @@ resource "aws_opsworks_stack" "tf-acc" {
region = "us-east-1" region = "us-east-1"
service_role_arn = "${aws_iam_role.opsworks_service.arn}" service_role_arn = "${aws_iam_role.opsworks_service.arn}"
default_instance_profile_arn = "${aws_iam_instance_profile.opsworks_instance.arn}" default_instance_profile_arn = "${aws_iam_instance_profile.opsworks_instance.arn}"
default_availability_zone = "us-east-1c" default_availability_zone = "us-east-1a"
default_os = "Amazon Linux 2014.09" default_os = "Amazon Linux 2014.09"
default_root_device_type = "ebs" default_root_device_type = "ebs"
custom_json = "{\"key\": \"value\"}" custom_json = "{\"key\": \"value\"}"

View File

@ -0,0 +1,136 @@
package aws
import (
"log"
"github.com/hashicorp/terraform/helper/schema"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/opsworks"
)
func resourceAwsOpsworksUserProfile() *schema.Resource {
return &schema.Resource{
Create: resourceAwsOpsworksUserProfileCreate,
Read: resourceAwsOpsworksUserProfileRead,
Update: resourceAwsOpsworksUserProfileUpdate,
Delete: resourceAwsOpsworksUserProfileDelete,
Schema: map[string]*schema.Schema{
"id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"user_arn": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"allow_self_management": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"ssh_username": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"ssh_public_key": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
},
}
}
func resourceAwsOpsworksUserProfileRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*AWSClient).opsworksconn
req := &opsworks.DescribeUserProfilesInput{
IamUserArns: []*string{
aws.String(d.Id()),
},
}
log.Printf("[DEBUG] Reading OpsWorks user profile: %s", d.Id())
resp, err := client.DescribeUserProfiles(req)
if err != nil {
if awserr, ok := err.(awserr.Error); ok {
if awserr.Code() == "ResourceNotFoundException" {
log.Printf("[DEBUG] OpsWorks user profile (%s) not found", d.Id())
d.SetId("")
return nil
}
}
return err
}
for _, profile := range resp.UserProfiles {
d.Set("allow_self_management", profile.AllowSelfManagement)
d.Set("user_arn", profile.IamUserArn)
d.Set("ssh_public_key", profile.SshPublicKey)
d.Set("ssh_username", profile.SshUsername)
break
}
return nil
}
func resourceAwsOpsworksUserProfileCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*AWSClient).opsworksconn
req := &opsworks.CreateUserProfileInput{
AllowSelfManagement: aws.Bool(d.Get("allow_self_management").(bool)),
IamUserArn: aws.String(d.Get("user_arn").(string)),
SshPublicKey: aws.String(d.Get("ssh_public_key").(string)),
SshUsername: aws.String(d.Get("ssh_username").(string)),
}
resp, err := client.CreateUserProfile(req)
if err != nil {
return err
}
d.SetId(*resp.IamUserArn)
return resourceAwsOpsworksUserProfileUpdate(d, meta)
}
func resourceAwsOpsworksUserProfileUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*AWSClient).opsworksconn
req := &opsworks.UpdateUserProfileInput{
AllowSelfManagement: aws.Bool(d.Get("allow_self_management").(bool)),
IamUserArn: aws.String(d.Get("user_arn").(string)),
SshPublicKey: aws.String(d.Get("ssh_public_key").(string)),
SshUsername: aws.String(d.Get("ssh_username").(string)),
}
log.Printf("[DEBUG] Updating OpsWorks user profile: %s", req)
_, err := client.UpdateUserProfile(req)
if err != nil {
return err
}
return resourceAwsOpsworksUserProfileRead(d, meta)
}
func resourceAwsOpsworksUserProfileDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*AWSClient).opsworksconn
req := &opsworks.DeleteUserProfileInput{
IamUserArn: aws.String(d.Id()),
}
log.Printf("[DEBUG] Deleting OpsWorks user profile: %s", d.Id())
_, err := client.DeleteUserProfile(req)
return err
}

View File

@ -0,0 +1,37 @@
package aws
import (
"testing"
"github.com/hashicorp/terraform/helper/resource"
)
func TestAccAWSOpsworksUserProfile(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAwsOpsworksUserProfileCreate,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"aws_opsworks_user_profile.user", "ssh_public_key", "",
),
resource.TestCheckResourceAttr(
"aws_opsworks_user_profile.user", "ssh_username", "test-user",
),
resource.TestCheckResourceAttr(
"aws_opsworks_user_profile.user", "allow_self_management", "false",
),
),
},
},
})
}
var testAccAwsOpsworksUserProfileCreate = testAccAWSUserConfig + testAccAwsOpsworksStackConfigNoVpcCreate("tf-ops-acc-user-profile") + `
resource "aws_opsworks_user_profile" "user" {
user_arn = "${aws_iam_user.user.arn}"
ssh_username = "${aws_iam_user.user.name}"
}
`

View File

@ -0,0 +1,39 @@
---
layout: "aws"
page_title: "AWS: aws_opsworks_permission"
sidebar_current: "docs-aws-resource-opsworks-permission"
description: |-
Provides an OpsWorks permission resource.
-------------------------------------------
# aws\_opsworks\_permission
Provides an OpsWorks permission resource.
## Example Usage
```
resource "aws_opsworks_permission" "my_stack_permission" {
allow_ssh = true
allow_sudo = true
level = "iam_only"
user_arn = "${aws_iam_user.user.arn}"
stack_id = "${aws_opsworks_stack.stack.id}"
}
```
## Argument Reference
The following arguments are supported:
* `allow_ssh` - (Optional) Whethe the user is allowed to use SSH to communicate with the instance
* `allow_sudo` - (Optional) Whethe the user is allowed to use sudo to elevate privileges
* `user_arn` - (Required) The user's IAM ARN to set permissions for
* `level` - (Optional) The users permission level. Mus be one of `deny`, `show`, `deploy`, `manage`, `iam_only`
* `stack_id` - (Required) The stack to set the permissions for
## Attributes Reference
The following attributes are exported:
* `id` - The computed id of the permission. Please note that this is only used internally to identify the permission. This value is not used in aws.

View File

@ -0,0 +1,35 @@
---
layout: "aws"
page_title: "AWS: aws_opsworks_user_profile_"
sidebar_current: "docs-aws-resource-opsworks-user-profile"
description: |-
Provides an OpsWorks User Profile resource.
---------------------------------------------
# aws\_opsworks\_user\_profile
Provides an OpsWorks User Profile resource.
## Example Usage
```
resource "aws_opsworks_user_profile" "my_profile" {
user_arn = "${aws_iam_user.user.arn}"
ssh_username = "my_user"
}
```
## Argument Reference
The following arguments are supported:
* `user_arn` - (Required) The user's IAM ARN
* `allow_self_management` - (Optional) Whether users can specify their own SSH public key through the My Settings page
* `ssh_username` - (Required) The ssh username, with witch this user wants to log in
* `ssh_public_key` - (Optional) The users public key
## Attributes Reference
The following attributes are exported:
* `id` - Same value as `user_arn`