provider/aws: Add aws elastic beanstalk solution stack (#14944)

* Add aws elastic beanstalk solution stack

Signed-off-by: Thomas Schaaf <thomaschaaf@Thomass-MBP.fritz.box>

* Fix incorrect naming

Signed-off-by: Thomas Schaaf <thomaschaaf@Thomass-MBP.fritz.box>

* Use unique go variable/function names

Signed-off-by: Thomas Schaaf <thomaschaaf@Thomass-MacBook-Pro.local>

* Add docs to sidebar

* Sort provider by alphabet

* Fix indent

* Add required statement

* Fix acceptance test
This commit is contained in:
Thomas Schaaf 2017-06-01 01:23:06 +02:00 committed by Paul Stack
parent c4c3c3f24d
commit 79c91e11c8
13 changed files with 287 additions and 38 deletions

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=countHookAction hook_count_action.go"; DO NOT EDIT.
// Code generated by "stringer -type=countHookAction hook_count_action.go"; DO NOT EDIT
package local

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=OperationType operation_type.go"; DO NOT EDIT.
// Code generated by "stringer -type=OperationType operation_type.go"; DO NOT EDIT
package backend

View File

@ -0,0 +1,105 @@
package aws
import (
"fmt"
"log"
"regexp"
"github.com/aws/aws-sdk-go/service/elasticbeanstalk"
"github.com/hashicorp/terraform/helper/schema"
)
func dataSourceAwsElasticBeanstalkSolutionStack() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsElasticBeanstalkSolutionStackRead,
Schema: map[string]*schema.Schema{
"name_regex": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validateSolutionStackNameRegex,
},
"most_recent": {
Type: schema.TypeBool,
Optional: true,
Default: false,
ForceNew: true,
},
// Computed values.
"name": {
Type: schema.TypeString,
Computed: true,
},
},
}
}
// dataSourceAwsElasticBeanstalkSolutionStackRead performs the API lookup.
func dataSourceAwsElasticBeanstalkSolutionStackRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).elasticbeanstalkconn
nameRegex := d.Get("name_regex")
var params *elasticbeanstalk.ListAvailableSolutionStacksInput
resp, err := conn.ListAvailableSolutionStacks(params)
if err != nil {
return err
}
var filteredSolutionStacks []*string
r := regexp.MustCompile(nameRegex.(string))
for _, solutionStack := range resp.SolutionStacks {
if r.MatchString(*solutionStack) {
filteredSolutionStacks = append(filteredSolutionStacks, solutionStack)
}
}
var solutionStack *string
if len(filteredSolutionStacks) < 1 {
return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.")
}
if len(filteredSolutionStacks) == 1 {
// Query returned single result.
solutionStack = filteredSolutionStacks[0]
} else {
recent := d.Get("most_recent").(bool)
log.Printf("[DEBUG] aws_elastic_beanstalk_solution_stack - multiple results found and `most_recent` is set to: %t", recent)
if recent {
solutionStack = mostRecentSolutionStack(filteredSolutionStacks)
} else {
return fmt.Errorf("Your query returned more than one result. Please try a more " +
"specific search criteria, or set `most_recent` attribute to true.")
}
}
log.Printf("[DEBUG] aws_elastic_beanstalk_solution_stack - Single solution stack found: %s", *solutionStack)
return solutionStackDescriptionAttributes(d, solutionStack)
}
// Returns the most recent solution stack out of a slice of stacks.
func mostRecentSolutionStack(solutionStacks []*string) *string {
return solutionStacks[0]
}
// populate the numerous fields that the image description returns.
func solutionStackDescriptionAttributes(d *schema.ResourceData, solutionStack *string) error {
// Simple attributes first
d.SetId(*solutionStack)
d.Set("name", solutionStack)
return nil
}
func validateSolutionStackNameRegex(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if _, err := regexp.Compile(value); err != nil {
errors = append(errors, fmt.Errorf(
"%q contains an invalid regular expression: %s",
k, err))
}
return
}

View File

@ -0,0 +1,103 @@
package aws
import (
"fmt"
"regexp"
"testing"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccAWSElasticBeanstalkSolutionStackDataSource(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCheckAwsElasticBeanstalkSolutionStackDataSourceConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsElasticBeanstalkSolutionStackDataSourceID("data.aws_elastic_beanstalk_solution_stack.multi_docker"),
resource.TestMatchResourceAttr("data.aws_elastic_beanstalk_solution_stack.multi_docker", "name", regexp.MustCompile("^64bit Amazon Linux (.*) Multi-container Docker (.*)$")),
),
},
},
})
}
func TestResourceValidateSolutionStackNameRegex(t *testing.T) {
type testCases struct {
Value string
ErrCount int
}
invalidCases := []testCases{
{
Value: `\`,
ErrCount: 1,
},
{
Value: `**`,
ErrCount: 1,
},
{
Value: `(.+`,
ErrCount: 1,
},
}
for _, tc := range invalidCases {
_, errors := validateSolutionStackNameRegex(tc.Value, "name_regex")
if len(errors) != tc.ErrCount {
t.Fatalf("Expected %q to trigger a validation error.", tc.Value)
}
}
validCases := []testCases{
{
Value: `\/`,
ErrCount: 0,
},
{
Value: `.*`,
ErrCount: 0,
},
{
Value: `\b(?:\d{1,3}\.){3}\d{1,3}\b`,
ErrCount: 0,
},
}
for _, tc := range validCases {
_, errors := validateSolutionStackNameRegex(tc.Value, "name_regex")
if len(errors) != tc.ErrCount {
t.Fatalf("Expected %q not to trigger a validation error.", tc.Value)
}
}
}
func testAccCheckAwsElasticBeanstalkSolutionStackDataSourceDestroy(s *terraform.State) error {
return nil
}
func testAccCheckAwsElasticBeanstalkSolutionStackDataSourceID(n string) resource.TestCheckFunc {
// Wait for solution stacks
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Can't find solution stack data source: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("Solution stack data source ID not set")
}
return nil
}
}
const testAccCheckAwsElasticBeanstalkSolutionStackDataSourceConfig = `
data "aws_elastic_beanstalk_solution_stack" "multi_docker" {
most_recent = true
name_regex = "^64bit Amazon Linux (.*) Multi-container Docker (.*)$"
}
`

View File

@ -181,35 +181,36 @@ func Provider() terraform.ResourceProvider {
"aws_ecs_task_definition": dataSourceAwsEcsTaskDefinition(),
"aws_efs_file_system": dataSourceAwsEfsFileSystem(),
"aws_eip": dataSourceAwsEip(),
"aws_elasticache_cluster": dataSourceAwsElastiCacheCluster(),
"aws_elb_hosted_zone_id": dataSourceAwsElbHostedZoneId(),
"aws_elb_service_account": dataSourceAwsElbServiceAccount(),
"aws_iam_account_alias": dataSourceAwsIamAccountAlias(),
"aws_iam_policy_document": dataSourceAwsIamPolicyDocument(),
"aws_iam_role": dataSourceAwsIAMRole(),
"aws_iam_server_certificate": dataSourceAwsIAMServerCertificate(),
"aws_instance": dataSourceAwsInstance(),
"aws_ip_ranges": dataSourceAwsIPRanges(),
"aws_kinesis_stream": dataSourceAwsKinesisStream(),
"aws_kms_alias": dataSourceAwsKmsAlias(),
"aws_kms_ciphertext": dataSourceAwsKmsCiphetext(),
"aws_kms_secret": dataSourceAwsKmsSecret(),
"aws_partition": dataSourceAwsPartition(),
"aws_prefix_list": dataSourceAwsPrefixList(),
"aws_redshift_service_account": dataSourceAwsRedshiftServiceAccount(),
"aws_region": dataSourceAwsRegion(),
"aws_route_table": dataSourceAwsRouteTable(),
"aws_route53_zone": dataSourceAwsRoute53Zone(),
"aws_s3_bucket_object": dataSourceAwsS3BucketObject(),
"aws_sns_topic": dataSourceAwsSnsTopic(),
"aws_subnet": dataSourceAwsSubnet(),
"aws_subnet_ids": dataSourceAwsSubnetIDs(),
"aws_security_group": dataSourceAwsSecurityGroup(),
"aws_vpc": dataSourceAwsVpc(),
"aws_vpc_endpoint": dataSourceAwsVpcEndpoint(),
"aws_vpc_endpoint_service": dataSourceAwsVpcEndpointService(),
"aws_vpc_peering_connection": dataSourceAwsVpcPeeringConnection(),
"aws_vpn_gateway": dataSourceAwsVpnGateway(),
"aws_elastic_beanstalk_solution_stack": dataSourceAwsElasticBeanstalkSolutionStack(),
"aws_elasticache_cluster": dataSourceAwsElastiCacheCluster(),
"aws_elb_hosted_zone_id": dataSourceAwsElbHostedZoneId(),
"aws_elb_service_account": dataSourceAwsElbServiceAccount(),
"aws_iam_account_alias": dataSourceAwsIamAccountAlias(),
"aws_iam_policy_document": dataSourceAwsIamPolicyDocument(),
"aws_iam_role": dataSourceAwsIAMRole(),
"aws_iam_server_certificate": dataSourceAwsIAMServerCertificate(),
"aws_instance": dataSourceAwsInstance(),
"aws_ip_ranges": dataSourceAwsIPRanges(),
"aws_kinesis_stream": dataSourceAwsKinesisStream(),
"aws_kms_alias": dataSourceAwsKmsAlias(),
"aws_kms_ciphertext": dataSourceAwsKmsCiphetext(),
"aws_kms_secret": dataSourceAwsKmsSecret(),
"aws_partition": dataSourceAwsPartition(),
"aws_prefix_list": dataSourceAwsPrefixList(),
"aws_redshift_service_account": dataSourceAwsRedshiftServiceAccount(),
"aws_region": dataSourceAwsRegion(),
"aws_route_table": dataSourceAwsRouteTable(),
"aws_route53_zone": dataSourceAwsRoute53Zone(),
"aws_s3_bucket_object": dataSourceAwsS3BucketObject(),
"aws_sns_topic": dataSourceAwsSnsTopic(),
"aws_subnet": dataSourceAwsSubnet(),
"aws_subnet_ids": dataSourceAwsSubnetIDs(),
"aws_security_group": dataSourceAwsSecurityGroup(),
"aws_vpc": dataSourceAwsVpc(),
"aws_vpc_endpoint": dataSourceAwsVpcEndpoint(),
"aws_vpc_endpoint_service": dataSourceAwsVpcEndpointService(),
"aws_vpc_peering_connection": dataSourceAwsVpcPeeringConnection(),
"aws_vpn_gateway": dataSourceAwsVpnGateway(),
},
ResourcesMap: map[string]*schema.Resource{

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=ResourceMode -output=resource_mode_string.go resource_mode.go"; DO NOT EDIT.
// Code generated by "stringer -type=ResourceMode -output=resource_mode_string.go resource_mode.go"; DO NOT EDIT
package config

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=getSource resource_data_get_source.go"; DO NOT EDIT.
// Code generated by "stringer -type=getSource resource_data_get_source.go"; DO NOT EDIT
package schema

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=ValueType valuetype.go"; DO NOT EDIT.
// Code generated by "stringer -type=ValueType valuetype.go"; DO NOT EDIT
package schema

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=GraphType context_graph_type.go"; DO NOT EDIT.
// Code generated by "stringer -type=GraphType context_graph_type.go"; DO NOT EDIT
package terraform

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=InstanceType instancetype.go"; DO NOT EDIT.
// Code generated by "stringer -type=InstanceType instancetype.go"; DO NOT EDIT
package terraform

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type=walkOperation graph_walk_operation.go"; DO NOT EDIT.
// Code generated by "stringer -type=walkOperation graph_walk_operation.go"; DO NOT EDIT
package terraform

View File

@ -0,0 +1,37 @@
---
layout: "aws"
page_title: "AWS: aws_elastic_beanstalk_solution_stack"
sidebar_current: "docs-aws-datasource-elastic-beanstalk-solution-stack"
description: |-
Get an elastic beanstalk solution stack.
---
# aws\_elastic\_beanstalk\_solution\_stack
Use this data source to get the name of a elastic beanstalk solution stack.
## Example Usage
```hcl
data "aws_elastic_beanstalk_solution_stack" "multi_docker" {
most_recent = true
name_regex = "^64bit Amazon Linux (.*) Multi-container Docker (.*)$"
}
```
## Argument Reference
* `most_recent` - (Optional) If more than one result is returned, use the most
recent solution stack.
* `name_regex` - A regex string to apply to the solution stack list returned
by AWS.
~> **NOTE:** If more or less than a single match is returned by the search,
Terraform will fail. Ensure that your search is specific enough to return
a single solution stack, or use `most_recent` to choose the most recent one.
## Attributes Reference
* `name` - The name of the solution stack.

View File

@ -80,6 +80,9 @@
<li<%= sidebar_current("docs-aws-datasource-eip") %>>
<a href="/docs/providers/aws/d/eip.html">aws_eip</a>
</li>
<li<%= sidebar_current("docs-aws-datasource-elastic-beanstalk-solution-stack") %>>
<a href="/docs/providers/aws/d/elastic_beanstalk_solution_stack.html">aws_elastic_beanstalk_solution_stack</a>
</li>
<li<%= sidebar_current("docs-aws-datasource-elasticache-cluster") %>>
<a href="/docs/providers/aws/d/elasticache_cluster.html">aws_elasticache_cluster</a>
</li>