provider/aws: Add EBS Volume support for EMR Instance Groups
Adds EBS Volume support and tests for EMR Instnace Groups ``` $ make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSEMRInstanceGroup_ebsBasic' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2017/01/25 10:14:58 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSEMRInstanceGroup_ebsBasic -timeout 120m === RUN TestAccAWSEMRInstanceGroup_ebsBasic --- PASS: TestAccAWSEMRInstanceGroup_ebsBasic (675.14s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws 675.171s ```
This commit is contained in:
parent
27e29420e5
commit
a60f35e694
|
@ -22,38 +22,100 @@ func resourceAwsEMRInstanceGroup() *schema.Resource {
|
||||||
Update: resourceAwsEMRInstanceGroupUpdate,
|
Update: resourceAwsEMRInstanceGroupUpdate,
|
||||||
Delete: resourceAwsEMRInstanceGroupDelete,
|
Delete: resourceAwsEMRInstanceGroupDelete,
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"cluster_id": &schema.Schema{
|
"cluster_id": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: true,
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
},
|
},
|
||||||
"instance_type": &schema.Schema{
|
"instance_type": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Required: true,
|
Required: true,
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
},
|
},
|
||||||
"instance_count": &schema.Schema{
|
"instance_count": {
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Default: 0,
|
Default: 0,
|
||||||
},
|
},
|
||||||
"running_instance_count": &schema.Schema{
|
"running_instance_count": {
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
"status": &schema.Schema{
|
"status": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
"name": &schema.Schema{
|
"name": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
},
|
},
|
||||||
|
"ebs_optimized": {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"ebs_config": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"iops": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validateAwsEmrEbsVolumeType,
|
||||||
|
},
|
||||||
|
"volumes_per_instance": {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Populates an emr.EbsConfiguration struct
|
||||||
|
func readEmrEBSConfig(d *schema.ResourceData) *emr.EbsConfiguration {
|
||||||
|
result := &emr.EbsConfiguration{}
|
||||||
|
if v, ok := d.GetOk("ebs_optimized"); ok {
|
||||||
|
result.EbsOptimized = aws.Bool(v.(bool))
|
||||||
|
}
|
||||||
|
|
||||||
|
ebsConfigs := make([]*emr.EbsBlockDeviceConfig, 0)
|
||||||
|
if rawConfig, ok := d.GetOk("ebs_config"); ok {
|
||||||
|
configList := rawConfig.(*schema.Set).List()
|
||||||
|
for _, config := range configList {
|
||||||
|
conf := config.(map[string]interface{})
|
||||||
|
ebs := &emr.EbsBlockDeviceConfig{}
|
||||||
|
volumeSpec := &emr.VolumeSpecification{
|
||||||
|
SizeInGB: aws.Int64(int64(conf["size"].(int))),
|
||||||
|
VolumeType: aws.String(conf["type"].(string)),
|
||||||
|
}
|
||||||
|
if v, ok := conf["iops"].(int); ok && v != 0 {
|
||||||
|
volumeSpec.Iops = aws.Int64(int64(v))
|
||||||
|
}
|
||||||
|
if v, ok := conf["volumes_per_instance"].(int); ok && v != 0 {
|
||||||
|
ebs.VolumesPerInstance = aws.Int64(int64(v))
|
||||||
|
}
|
||||||
|
ebs.VolumeSpecification = volumeSpec
|
||||||
|
ebsConfigs = append(ebsConfigs, ebs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.EbsBlockDeviceConfigs = ebsConfigs
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func resourceAwsEMRInstanceGroupCreate(d *schema.ResourceData, meta interface{}) error {
|
func resourceAwsEMRInstanceGroupCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
conn := meta.(*AWSClient).emrconn
|
conn := meta.(*AWSClient).emrconn
|
||||||
|
|
||||||
|
@ -62,13 +124,16 @@ func resourceAwsEMRInstanceGroupCreate(d *schema.ResourceData, meta interface{})
|
||||||
instanceCount := d.Get("instance_count").(int)
|
instanceCount := d.Get("instance_count").(int)
|
||||||
groupName := d.Get("name").(string)
|
groupName := d.Get("name").(string)
|
||||||
|
|
||||||
|
ebsConfig := readEmrEBSConfig(d)
|
||||||
|
|
||||||
params := &emr.AddInstanceGroupsInput{
|
params := &emr.AddInstanceGroupsInput{
|
||||||
InstanceGroups: []*emr.InstanceGroupConfig{
|
InstanceGroups: []*emr.InstanceGroupConfig{
|
||||||
{
|
{
|
||||||
InstanceRole: aws.String("TASK"),
|
InstanceRole: aws.String("TASK"),
|
||||||
InstanceCount: aws.Int64(int64(instanceCount)),
|
InstanceCount: aws.Int64(int64(instanceCount)),
|
||||||
InstanceType: aws.String(instanceType),
|
InstanceType: aws.String(instanceType),
|
||||||
Name: aws.String(groupName),
|
Name: aws.String(groupName),
|
||||||
|
EbsConfiguration: ebsConfig,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
JobFlowId: aws.String(clusterId),
|
JobFlowId: aws.String(clusterId),
|
||||||
|
|
|
@ -21,7 +21,7 @@ func TestAccAWSEMRInstanceGroup_basic(t *testing.T) {
|
||||||
Providers: testAccProviders,
|
Providers: testAccProviders,
|
||||||
CheckDestroy: testAccCheckAWSEmrInstanceGroupDestroy,
|
CheckDestroy: testAccCheckAWSEmrInstanceGroupDestroy,
|
||||||
Steps: []resource.TestStep{
|
Steps: []resource.TestStep{
|
||||||
resource.TestStep{
|
{
|
||||||
Config: testAccAWSEmrInstanceGroupConfig(rInt),
|
Config: testAccAWSEmrInstanceGroupConfig(rInt),
|
||||||
Check: testAccCheckAWSEmrInstanceGroupExists("aws_emr_instance_group.task", &ig),
|
Check: testAccCheckAWSEmrInstanceGroupExists("aws_emr_instance_group.task", &ig),
|
||||||
},
|
},
|
||||||
|
@ -29,6 +29,28 @@ func TestAccAWSEMRInstanceGroup_basic(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccAWSEMRInstanceGroup_ebsBasic(t *testing.T) {
|
||||||
|
var ig emr.InstanceGroup
|
||||||
|
rInt := acctest.RandInt()
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSEmrInstanceGroupDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: testAccAWSEmrInstanceGroupConfig_ebsBasic(rInt),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSEmrInstanceGroupExists("aws_emr_instance_group.task", &ig),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"aws_emr_instance_group.task", "ebs_config.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"aws_emr_instance_group.task", "ebs_optimized", "true"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func testAccCheckAWSEmrInstanceGroupDestroy(s *terraform.State) error {
|
func testAccCheckAWSEmrInstanceGroupDestroy(s *terraform.State) error {
|
||||||
conn := testAccProvider.Meta().(*AWSClient).emrconn
|
conn := testAccProvider.Meta().(*AWSClient).emrconn
|
||||||
|
|
||||||
|
@ -85,8 +107,7 @@ func testAccCheckAWSEmrInstanceGroupExists(n string, v *emr.InstanceGroup) resou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAccAWSEmrInstanceGroupConfig(r int) string {
|
const testAccAWSEmrInstanceGroupBase = `
|
||||||
return fmt.Sprintf(`
|
|
||||||
provider "aws" {
|
provider "aws" {
|
||||||
region = "us-west-2"
|
region = "us-west-2"
|
||||||
}
|
}
|
||||||
|
@ -126,12 +147,6 @@ resource "aws_emr_cluster" "tf-test-cluster" {
|
||||||
depends_on = ["aws_internet_gateway.gw"]
|
depends_on = ["aws_internet_gateway.gw"]
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_emr_instance_group" "task" {
|
|
||||||
cluster_id = "${aws_emr_cluster.tf-test-cluster.id}"
|
|
||||||
instance_count = 1
|
|
||||||
instance_type = "m3.xlarge"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "aws_security_group" "allow_all" {
|
resource "aws_security_group" "allow_all" {
|
||||||
name = "allow_all"
|
name = "allow_all"
|
||||||
description = "Allow all inbound traffic"
|
description = "Allow all inbound traffic"
|
||||||
|
@ -352,5 +367,30 @@ resource "aws_iam_policy" "iam_emr_profile_policy" {
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
EOT
|
EOT
|
||||||
}`, r, r, r, r, r, r)
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
func testAccAWSEmrInstanceGroupConfig(r int) string {
|
||||||
|
return fmt.Sprintf(testAccAWSEmrInstanceGroupBase+`
|
||||||
|
resource "aws_emr_instance_group" "task" {
|
||||||
|
cluster_id = "${aws_emr_cluster.tf-test-cluster.id}"
|
||||||
|
instance_count = 1
|
||||||
|
instance_type = "m3.xlarge"
|
||||||
|
}
|
||||||
|
`, r, r, r, r, r, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccAWSEmrInstanceGroupConfig_ebsBasic(r int) string {
|
||||||
|
return fmt.Sprintf(testAccAWSEmrInstanceGroupBase+`
|
||||||
|
resource "aws_emr_instance_group" "task" {
|
||||||
|
cluster_id = "${aws_emr_cluster.tf-test-cluster.id}"
|
||||||
|
instance_count = 1
|
||||||
|
instance_type = "m3.xlarge"
|
||||||
|
ebs_optimized = true
|
||||||
|
ebs_config {
|
||||||
|
"size" = 10,
|
||||||
|
"type" = "gp2",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, r, r, r, r, r, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -727,3 +727,19 @@ func validateAwsEcsPlacementStrategy(stratType, stratField string) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateAwsEmrEbsVolumeType(v interface{}, k string) (ws []string, errors []error) {
|
||||||
|
validTypes := map[string]struct{}{
|
||||||
|
"gp2": {},
|
||||||
|
"io1": {},
|
||||||
|
"standard": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
value := v.(string)
|
||||||
|
|
||||||
|
if _, ok := validTypes[value]; !ok {
|
||||||
|
errors = append(errors, fmt.Errorf(
|
||||||
|
"%q must be one of ['gp2', 'io1', 'standard']", k))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -1172,3 +1172,48 @@ func TestValidateEcsPlacementStrategy(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateEmrEbsVolumeType(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
VolType string
|
||||||
|
ErrCount int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
VolType: "gp2",
|
||||||
|
ErrCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VolType: "io1",
|
||||||
|
ErrCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VolType: "standard",
|
||||||
|
ErrCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VolType: "stand",
|
||||||
|
ErrCount: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VolType: "io",
|
||||||
|
ErrCount: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VolType: "gp1",
|
||||||
|
ErrCount: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
VolType: "fast-disk",
|
||||||
|
ErrCount: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
_, errors := validateAwsEmrEbsVolumeType(tc.VolType, "volume")
|
||||||
|
|
||||||
|
if len(errors) != tc.ErrCount {
|
||||||
|
t.Fatalf("Expected %d errors, got %d: %s", tc.ErrCount, len(errors), errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue