github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_api_gateway_integration.go (about)

     1  package aws
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"log"
     7  	"time"
     8  
     9  	"github.com/aws/aws-sdk-go/aws"
    10  	"github.com/aws/aws-sdk-go/aws/awserr"
    11  	"github.com/aws/aws-sdk-go/service/apigateway"
    12  	"github.com/hashicorp/terraform/helper/resource"
    13  	"github.com/hashicorp/terraform/helper/schema"
    14  	"strings"
    15  )
    16  
    17  func resourceAwsApiGatewayIntegration() *schema.Resource {
    18  	return &schema.Resource{
    19  		Create: resourceAwsApiGatewayIntegrationCreate,
    20  		Read:   resourceAwsApiGatewayIntegrationRead,
    21  		Update: resourceAwsApiGatewayIntegrationUpdate,
    22  		Delete: resourceAwsApiGatewayIntegrationDelete,
    23  
    24  		Schema: map[string]*schema.Schema{
    25  			"rest_api_id": {
    26  				Type:     schema.TypeString,
    27  				Required: true,
    28  				ForceNew: true,
    29  			},
    30  
    31  			"resource_id": {
    32  				Type:     schema.TypeString,
    33  				Required: true,
    34  				ForceNew: true,
    35  			},
    36  
    37  			"http_method": {
    38  				Type:         schema.TypeString,
    39  				Required:     true,
    40  				ForceNew:     true,
    41  				ValidateFunc: validateHTTPMethod,
    42  			},
    43  
    44  			"type": {
    45  				Type:         schema.TypeString,
    46  				Required:     true,
    47  				ForceNew:     true,
    48  				ValidateFunc: validateApiGatewayIntegrationType,
    49  			},
    50  
    51  			"uri": {
    52  				Type:     schema.TypeString,
    53  				Optional: true,
    54  				ForceNew: true,
    55  			},
    56  
    57  			"credentials": {
    58  				Type:     schema.TypeString,
    59  				Optional: true,
    60  				ForceNew: true,
    61  			},
    62  
    63  			"integration_http_method": {
    64  				Type:         schema.TypeString,
    65  				Optional:     true,
    66  				ForceNew:     true,
    67  				ValidateFunc: validateHTTPMethod,
    68  			},
    69  
    70  			"request_templates": {
    71  				Type:     schema.TypeMap,
    72  				Optional: true,
    73  				Elem:     schema.TypeString,
    74  			},
    75  
    76  			"request_parameters": {
    77  				Type:          schema.TypeMap,
    78  				Elem:          schema.TypeString,
    79  				Optional:      true,
    80  				ConflictsWith: []string{"request_parameters_in_json"},
    81  			},
    82  
    83  			"request_parameters_in_json": {
    84  				Type:          schema.TypeString,
    85  				Optional:      true,
    86  				ConflictsWith: []string{"request_parameters"},
    87  				Deprecated:    "Use field request_parameters instead",
    88  			},
    89  
    90  			"content_handling": {
    91  				Type:         schema.TypeString,
    92  				Optional:     true,
    93  				ForceNew:     true,
    94  				ValidateFunc: validateApiGatewayIntegrationContentHandling,
    95  			},
    96  
    97  			"passthrough_behavior": {
    98  				Type:         schema.TypeString,
    99  				Optional:     true,
   100  				Computed:     true,
   101  				ForceNew:     true,
   102  				ValidateFunc: validateApiGatewayIntegrationPassthroughBehavior,
   103  			},
   104  		},
   105  	}
   106  }
   107  
   108  func resourceAwsApiGatewayIntegrationCreate(d *schema.ResourceData, meta interface{}) error {
   109  	conn := meta.(*AWSClient).apigateway
   110  
   111  	log.Print("[DEBUG] Creating API Gateway Integration")
   112  	var integrationHttpMethod *string
   113  	if v, ok := d.GetOk("integration_http_method"); ok {
   114  		integrationHttpMethod = aws.String(v.(string))
   115  	}
   116  	var uri *string
   117  	if v, ok := d.GetOk("uri"); ok {
   118  		uri = aws.String(v.(string))
   119  	}
   120  	templates := make(map[string]string)
   121  	for k, v := range d.Get("request_templates").(map[string]interface{}) {
   122  		templates[k] = v.(string)
   123  	}
   124  
   125  	parameters := make(map[string]string)
   126  	if kv, ok := d.GetOk("request_parameters"); ok {
   127  		for k, v := range kv.(map[string]interface{}) {
   128  			parameters[k] = v.(string)
   129  		}
   130  	}
   131  
   132  	if v, ok := d.GetOk("request_parameters_in_json"); ok {
   133  		if err := json.Unmarshal([]byte(v.(string)), &parameters); err != nil {
   134  			return fmt.Errorf("Error unmarshaling request_parameters_in_json: %s", err)
   135  		}
   136  	}
   137  
   138  	var passthroughBehavior *string
   139  	if v, ok := d.GetOk("passthrough_behavior"); ok {
   140  		passthroughBehavior = aws.String(v.(string))
   141  	}
   142  
   143  	var credentials *string
   144  	if val, ok := d.GetOk("credentials"); ok {
   145  		credentials = aws.String(val.(string))
   146  	}
   147  
   148  	var contentHandling *string
   149  	if val, ok := d.GetOk("content_handling"); ok {
   150  		contentHandling = aws.String(val.(string))
   151  	}
   152  
   153  	_, err := conn.PutIntegration(&apigateway.PutIntegrationInput{
   154  		HttpMethod: aws.String(d.Get("http_method").(string)),
   155  		ResourceId: aws.String(d.Get("resource_id").(string)),
   156  		RestApiId:  aws.String(d.Get("rest_api_id").(string)),
   157  		Type:       aws.String(d.Get("type").(string)),
   158  		IntegrationHttpMethod: integrationHttpMethod,
   159  		Uri:                 uri,
   160  		RequestParameters:   aws.StringMap(parameters),
   161  		RequestTemplates:    aws.StringMap(templates),
   162  		Credentials:         credentials,
   163  		CacheNamespace:      nil,
   164  		CacheKeyParameters:  nil,
   165  		PassthroughBehavior: passthroughBehavior,
   166  		ContentHandling:     contentHandling,
   167  	})
   168  	if err != nil {
   169  		return fmt.Errorf("Error creating API Gateway Integration: %s", err)
   170  	}
   171  
   172  	d.SetId(fmt.Sprintf("agi-%s-%s-%s", d.Get("rest_api_id").(string), d.Get("resource_id").(string), d.Get("http_method").(string)))
   173  
   174  	return resourceAwsApiGatewayIntegrationRead(d, meta)
   175  }
   176  
   177  func resourceAwsApiGatewayIntegrationRead(d *schema.ResourceData, meta interface{}) error {
   178  	conn := meta.(*AWSClient).apigateway
   179  
   180  	log.Printf("[DEBUG] Reading API Gateway Integration: %s", d.Id())
   181  	integration, err := conn.GetIntegration(&apigateway.GetIntegrationInput{
   182  		HttpMethod: aws.String(d.Get("http_method").(string)),
   183  		ResourceId: aws.String(d.Get("resource_id").(string)),
   184  		RestApiId:  aws.String(d.Get("rest_api_id").(string)),
   185  	})
   186  	if err != nil {
   187  		if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NotFoundException" {
   188  			d.SetId("")
   189  			return nil
   190  		}
   191  		return err
   192  	}
   193  	log.Printf("[DEBUG] Received API Gateway Integration: %s", integration)
   194  	d.SetId(fmt.Sprintf("agi-%s-%s-%s", d.Get("rest_api_id").(string), d.Get("resource_id").(string), d.Get("http_method").(string)))
   195  
   196  	// AWS converts "" to null on their side, convert it back
   197  	if v, ok := integration.RequestTemplates["application/json"]; ok && v == nil {
   198  		integration.RequestTemplates["application/json"] = aws.String("")
   199  	}
   200  
   201  	d.Set("request_templates", aws.StringValueMap(integration.RequestTemplates))
   202  	d.Set("type", integration.Type)
   203  	d.Set("request_parameters", aws.StringValueMap(integration.RequestParameters))
   204  	d.Set("request_parameters_in_json", aws.StringValueMap(integration.RequestParameters))
   205  	d.Set("passthrough_behavior", integration.PassthroughBehavior)
   206  
   207  	if integration.Uri != nil {
   208  		d.Set("uri", integration.Uri)
   209  	}
   210  
   211  	if integration.Credentials != nil {
   212  		d.Set("credentials", integration.Credentials)
   213  	}
   214  
   215  	if integration.ContentHandling != nil {
   216  		d.Set("content_handling", integration.ContentHandling)
   217  	}
   218  
   219  	return nil
   220  }
   221  
   222  func resourceAwsApiGatewayIntegrationUpdate(d *schema.ResourceData, meta interface{}) error {
   223  	conn := meta.(*AWSClient).apigateway
   224  
   225  	log.Printf("[DEBUG] Updating API Gateway Integration: %s", d.Id())
   226  	operations := make([]*apigateway.PatchOperation, 0)
   227  
   228  	// https://docs.aws.amazon.com/apigateway/api-reference/link-relation/integration-update/#remarks
   229  	// According to the above documentation, only a few parts are addable / removable.
   230  	if d.HasChange("request_templates") {
   231  		o, n := d.GetChange("request_templates")
   232  		prefix := "requestTemplates"
   233  
   234  		os := o.(map[string]interface{})
   235  		ns := n.(map[string]interface{})
   236  
   237  		// Handle Removal
   238  		for k := range os {
   239  			if _, ok := ns[k]; !ok {
   240  				operations = append(operations, &apigateway.PatchOperation{
   241  					Op:   aws.String("remove"),
   242  					Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))),
   243  				})
   244  			}
   245  		}
   246  
   247  		for k, v := range ns {
   248  			// Handle replaces
   249  			if _, ok := os[k]; ok {
   250  				operations = append(operations, &apigateway.PatchOperation{
   251  					Op:    aws.String("replace"),
   252  					Path:  aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))),
   253  					Value: aws.String(v.(string)),
   254  				})
   255  			}
   256  
   257  			// Handle additions
   258  			if _, ok := os[k]; !ok {
   259  				operations = append(operations, &apigateway.PatchOperation{
   260  					Op:    aws.String("add"),
   261  					Path:  aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))),
   262  					Value: aws.String(v.(string)),
   263  				})
   264  			}
   265  		}
   266  	}
   267  
   268  	if d.HasChange("request_parameters") {
   269  		o, n := d.GetChange("request_parameters")
   270  		prefix := "requestParameters"
   271  
   272  		os := o.(map[string]interface{})
   273  		ns := n.(map[string]interface{})
   274  
   275  		// Handle Removal
   276  		for k := range os {
   277  			if _, ok := ns[k]; !ok {
   278  				operations = append(operations, &apigateway.PatchOperation{
   279  					Op:   aws.String("remove"),
   280  					Path: aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))),
   281  				})
   282  			}
   283  		}
   284  
   285  		for k, v := range ns {
   286  			// Handle replaces
   287  			if _, ok := os[k]; ok {
   288  				operations = append(operations, &apigateway.PatchOperation{
   289  					Op:    aws.String("replace"),
   290  					Path:  aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))),
   291  					Value: aws.String(v.(string)),
   292  				})
   293  			}
   294  
   295  			// Handle additions
   296  			if _, ok := os[k]; !ok {
   297  				operations = append(operations, &apigateway.PatchOperation{
   298  					Op:    aws.String("add"),
   299  					Path:  aws.String(fmt.Sprintf("/%s/%s", prefix, strings.Replace(k, "/", "~1", -1))),
   300  					Value: aws.String(v.(string)),
   301  				})
   302  			}
   303  		}
   304  	}
   305  
   306  	params := &apigateway.UpdateIntegrationInput{
   307  		HttpMethod:      aws.String(d.Get("http_method").(string)),
   308  		ResourceId:      aws.String(d.Get("resource_id").(string)),
   309  		RestApiId:       aws.String(d.Get("rest_api_id").(string)),
   310  		PatchOperations: operations,
   311  	}
   312  
   313  	_, err := conn.UpdateIntegration(params)
   314  	if err != nil {
   315  		return fmt.Errorf("Error updating API Gateway Integration: %s", err)
   316  	}
   317  
   318  	d.SetId(fmt.Sprintf("agi-%s-%s-%s", d.Get("rest_api_id").(string), d.Get("resource_id").(string), d.Get("http_method").(string)))
   319  
   320  	return resourceAwsApiGatewayIntegrationRead(d, meta)
   321  }
   322  
   323  func resourceAwsApiGatewayIntegrationDelete(d *schema.ResourceData, meta interface{}) error {
   324  	conn := meta.(*AWSClient).apigateway
   325  	log.Printf("[DEBUG] Deleting API Gateway Integration: %s", d.Id())
   326  
   327  	return resource.Retry(5*time.Minute, func() *resource.RetryError {
   328  		_, err := conn.DeleteIntegration(&apigateway.DeleteIntegrationInput{
   329  			HttpMethod: aws.String(d.Get("http_method").(string)),
   330  			ResourceId: aws.String(d.Get("resource_id").(string)),
   331  			RestApiId:  aws.String(d.Get("rest_api_id").(string)),
   332  		})
   333  		if err == nil {
   334  			return nil
   335  		}
   336  
   337  		apigatewayErr, ok := err.(awserr.Error)
   338  		if apigatewayErr.Code() == "NotFoundException" {
   339  			return nil
   340  		}
   341  
   342  		if !ok {
   343  			return resource.NonRetryableError(err)
   344  		}
   345  
   346  		return resource.NonRetryableError(err)
   347  	})
   348  }