Skip to content

Commit

Permalink
New Resource: appsync_graphql_api (#2494)
Browse files Browse the repository at this point in the history
* [WIP]New Resource: appsync_graphql_api

* testacc

* docs

* fix typo

* update

* Remove not-found check from Update
  • Loading branch information
atsushi-ishibashi authored and radeksimko committed Feb 12, 2018
1 parent d6a1a01 commit 8f671af
Show file tree
Hide file tree
Showing 6 changed files with 399 additions and 0 deletions.
3 changes: 3 additions & 0 deletions aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/aws/aws-sdk-go/service/acm"
"github.com/aws/aws-sdk-go/service/apigateway"
"github.com/aws/aws-sdk-go/service/applicationautoscaling"
"github.com/aws/aws-sdk-go/service/appsync"
"github.com/aws/aws-sdk-go/service/athena"
"github.com/aws/aws-sdk-go/service/autoscaling"
"github.com/aws/aws-sdk-go/service/batch"
Expand Down Expand Up @@ -208,6 +209,7 @@ type AWSClient struct {
athenaconn *athena.Athena
dxconn *directconnect.DirectConnect
mediastoreconn *mediastore.MediaStore
appsyncconn *appsync.AppSync
}

func (c *AWSClient) S3() *s3.S3 {
Expand Down Expand Up @@ -458,6 +460,7 @@ func (c *Config) Client() (interface{}, error) {
client.athenaconn = athena.New(sess)
client.dxconn = directconnect.New(sess)
client.mediastoreconn = mediastore.New(sess)
client.appsyncconn = appsync.New(sess)

// Workaround for https://github.com/aws/aws-sdk-go/issues/1376
client.kinesisconn.Handlers.Retry.PushBack(func(r *request.Request) {
Expand Down
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ func Provider() terraform.ResourceProvider {
"aws_appautoscaling_target": resourceAwsAppautoscalingTarget(),
"aws_appautoscaling_policy": resourceAwsAppautoscalingPolicy(),
"aws_appautoscaling_scheduled_action": resourceAwsAppautoscalingScheduledAction(),
"aws_appsync_graphql_api": resourceAwsAppsyncGraphqlApi(),
"aws_athena_database": resourceAwsAthenaDatabase(),
"aws_athena_named_query": resourceAwsAthenaNamedQuery(),
"aws_autoscaling_attachment": resourceAwsAutoscalingAttachment(),
Expand Down
195 changes: 195 additions & 0 deletions aws/resource_aws_appsync_graphql_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package aws

import (
"fmt"
"log"
"regexp"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/appsync"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsAppsyncGraphqlApi() *schema.Resource {
return &schema.Resource{
Create: resourceAwsAppsyncGraphqlApiCreate,
Read: resourceAwsAppsyncGraphqlApiRead,
Update: resourceAwsAppsyncGraphqlApiUpdate,
Delete: resourceAwsAppsyncGraphqlApiDelete,

Schema: map[string]*schema.Schema{
"authentication_type": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
appsync.AuthenticationTypeApiKey,
appsync.AuthenticationTypeAwsIam,
appsync.AuthenticationTypeAmazonCognitoUserPools,
}, false),
},
"name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if !regexp.MustCompile(`[_A-Za-z][_0-9A-Za-z]*`).MatchString(value) {
errors = append(errors, fmt.Errorf("%q must match [_A-Za-z][_0-9A-Za-z]*", k))
}
return
},
},
"user_pool_config": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"app_id_client_regex": {
Type: schema.TypeString,
Optional: true,
},
"aws_region": {
Type: schema.TypeString,
Required: true,
},
"default_action": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
appsync.DefaultActionAllow,
appsync.DefaultActionDeny,
}, false),
},
"user_pool_id": {
Type: schema.TypeString,
Required: true,
},
},
},
},
"arn": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceAwsAppsyncGraphqlApiCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).appsyncconn

input := &appsync.CreateGraphqlApiInput{
AuthenticationType: aws.String(d.Get("authentication_type").(string)),
Name: aws.String(d.Get("name").(string)),
}

if v, ok := d.GetOk("user_pool_config"); ok {
input.UserPoolConfig = expandAppsyncGraphqlApiUserPoolConfig(v.([]interface{}))
}

resp, err := conn.CreateGraphqlApi(input)
if err != nil {
return err
}

d.SetId(*resp.GraphqlApi.ApiId)
d.Set("arn", resp.GraphqlApi.Arn)
return nil
}

func resourceAwsAppsyncGraphqlApiRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).appsyncconn

input := &appsync.GetGraphqlApiInput{
ApiId: aws.String(d.Id()),
}

resp, err := conn.GetGraphqlApi(input)
if err != nil {
if isAWSErr(err, appsync.ErrCodeNotFoundException, "") {
log.Printf("[WARN] No such entity found for Appsync Graphql API (%s)", d.Id())
d.SetId("")
return nil
}
return err
}

d.Set("authentication_type", resp.GraphqlApi.AuthenticationType)
d.Set("name", resp.GraphqlApi.Name)
d.Set("user_pool_config", flattenAppsyncGraphqlApiUserPoolConfig(resp.GraphqlApi.UserPoolConfig))
d.Set("arn", resp.GraphqlApi.Arn)
return nil
}

func resourceAwsAppsyncGraphqlApiUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).appsyncconn

input := &appsync.UpdateGraphqlApiInput{
ApiId: aws.String(d.Id()),
Name: aws.String(d.Get("name").(string)),
}

if d.HasChange("authentication_type") {
input.AuthenticationType = aws.String(d.Get("authentication_type").(string))
}
if d.HasChange("user_pool_config") {
input.UserPoolConfig = expandAppsyncGraphqlApiUserPoolConfig(d.Get("user_pool_config").([]interface{}))
}

_, err := conn.UpdateGraphqlApi(input)
if err != nil {
return err
}

return resourceAwsAppsyncGraphqlApiRead(d, meta)
}

func resourceAwsAppsyncGraphqlApiDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).appsyncconn

input := &appsync.DeleteGraphqlApiInput{
ApiId: aws.String(d.Id()),
}
_, err := conn.DeleteGraphqlApi(input)
if err != nil {
if isAWSErr(err, appsync.ErrCodeNotFoundException, "") {
return nil
}
return err
}

return nil
}

func expandAppsyncGraphqlApiUserPoolConfig(config []interface{}) *appsync.UserPoolConfig {
if len(config) < 1 {
return nil
}
cg := config[0].(map[string]interface{})
upc := &appsync.UserPoolConfig{
AwsRegion: aws.String(cg["aws_region"].(string)),
DefaultAction: aws.String(cg["default_action"].(string)),
UserPoolId: aws.String(cg["user_pool_id"].(string)),
}
if v, ok := cg["app_id_client_regex"].(string); ok && v != "" {
upc.AppIdClientRegex = aws.String(v)
}
return upc
}

func flattenAppsyncGraphqlApiUserPoolConfig(upc *appsync.UserPoolConfig) []interface{} {
if upc == nil {
return []interface{}{}
}
m := make(map[string]interface{}, 1)

m["aws_region"] = *upc.AwsRegion
m["default_action"] = *upc.DefaultAction
m["user_pool_id"] = *upc.UserPoolId
if upc.AppIdClientRegex != nil {
m["app_id_client_regex"] = *upc.AppIdClientRegex
}

return []interface{}{m}
}
147 changes: 147 additions & 0 deletions aws/resource_aws_appsync_graphql_api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package aws

import (
"fmt"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/appsync"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestAccAwsAppsyncGraphqlApi_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAwsAppsyncGraphqlApiDestroy,
Steps: []resource.TestStep{
{
Config: testAccAppsyncGraphqlApiConfig_apikey(acctest.RandString(5)),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsAppsyncGraphqlApiExists("aws_appsync_graphql_api.test_apikey"),
resource.TestCheckResourceAttrSet("aws_appsync_graphql_api.test_apikey", "arn"),
),
},
},
})
}

func TestAccAwsAppsyncGraphqlApi_iam(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAwsAppsyncGraphqlApiDestroy,
Steps: []resource.TestStep{
{
Config: testAccAppsyncGraphqlApiConfig_iam(acctest.RandString(5)),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsAppsyncGraphqlApiExists("aws_appsync_graphql_api.test_iam"),
resource.TestCheckResourceAttrSet("aws_appsync_graphql_api.test_iam", "arn"),
),
},
},
})
}

func TestAccAwsAppsyncGraphqlApi_cognito(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAwsAppsyncGraphqlApiDestroy,
Steps: []resource.TestStep{
{
Config: testAccAppsyncGraphqlApiConfig_cognito(acctest.RandString(5)),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsAppsyncGraphqlApiExists("aws_appsync_graphql_api.test_cognito"),
resource.TestCheckResourceAttrSet("aws_appsync_graphql_api.test_cognito", "arn"),
),
},
},
})
}

func testAccCheckAwsAppsyncGraphqlApiDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).appsyncconn
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_appsync_graphql_api" {
continue
}

input := &appsync.GetGraphqlApiInput{
ApiId: aws.String(rs.Primary.ID),
}

_, err := conn.GetGraphqlApi(input)
if err != nil {
if isAWSErr(err, appsync.ErrCodeNotFoundException, "") {
return nil
}
return err
}
}
return nil
}

func testAccCheckAwsAppsyncGraphqlApiExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Not found: %s", name)
}

conn := testAccProvider.Meta().(*AWSClient).appsyncconn

input := &appsync.GetGraphqlApiInput{
ApiId: aws.String(rs.Primary.ID),
}

_, err := conn.GetGraphqlApi(input)
if err != nil {
return err
}

return nil
}
}

func testAccAppsyncGraphqlApiConfig_apikey(rName string) string {
return fmt.Sprintf(`
resource "aws_appsync_graphql_api" "test_apikey" {
authentication_type = "API_KEY"
name = "tf_appsync_%s"
}
`, rName)
}

func testAccAppsyncGraphqlApiConfig_iam(rName string) string {
return fmt.Sprintf(`
resource "aws_appsync_graphql_api" "test_iam" {
authentication_type = "AWS_IAM"
name = "tf_appsync_%s"
}
`, rName)
}

func testAccAppsyncGraphqlApiConfig_cognito(rName string) string {
return fmt.Sprintf(`
data "aws_region" "test" {
current = true
}
resource "aws_cognito_user_pool" "test" {
name = "tf-%s"
}
resource "aws_appsync_graphql_api" "test_cognito" {
authentication_type = "AMAZON_COGNITO_USER_POOLS"
name = "tf_appsync_%s"
user_pool_config {
aws_region = "${data.aws_region.test.name}"
default_action = "ALLOW"
user_pool_id = "${aws_cognito_user_pool.test.id}"
}
}
`, rName, rName)
}
9 changes: 9 additions & 0 deletions website/aws.erb
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,15 @@
</ul>
</li>

<li<%= sidebar_current("docs-aws-resource-appsync") %>>
<a href="#">AppSync Resources</a>
<ul class="nav nav-visible">
<li<%= sidebar_current("docs-aws-resource-appsync-graphql-api") %>>
<a href="/docs/providers/aws/r/appsync_graphql_api.html">aws_appsync_graphql_api</a>
</li>
</ul>
</li>

<li<%= sidebar_current("docs-aws-resource-athena") %>>
<a href="#">Athena Resources</a>
<ul class="nav nav-visible">
Expand Down
Loading

0 comments on commit 8f671af

Please sign in to comment.