github.com/jsoriano/terraform@v0.6.7-0.20151026070445-8b70867fdd95/builtin/providers/aws/resource_aws_lambda_function.go (about)

     1  package aws
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"log"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/aws/aws-sdk-go/aws"
    12  	"github.com/aws/aws-sdk-go/aws/awserr"
    13  	"github.com/aws/aws-sdk-go/service/lambda"
    14  	"github.com/mitchellh/go-homedir"
    15  
    16  	"github.com/hashicorp/terraform/helper/schema"
    17  )
    18  
    19  func resourceAwsLambdaFunction() *schema.Resource {
    20  	return &schema.Resource{
    21  		Create: resourceAwsLambdaFunctionCreate,
    22  		Read:   resourceAwsLambdaFunctionRead,
    23  		Update: resourceAwsLambdaFunctionUpdate,
    24  		Delete: resourceAwsLambdaFunctionDelete,
    25  
    26  		Schema: map[string]*schema.Schema{
    27  			"filename": &schema.Schema{
    28  				Type:     schema.TypeString,
    29  				Required: true,
    30  			},
    31  			"description": &schema.Schema{
    32  				Type:     schema.TypeString,
    33  				Optional: true,
    34  				ForceNew: true, // TODO make this editable
    35  			},
    36  			"function_name": &schema.Schema{
    37  				Type:     schema.TypeString,
    38  				Required: true,
    39  				ForceNew: true,
    40  			},
    41  			"handler": &schema.Schema{
    42  				Type:     schema.TypeString,
    43  				Required: true,
    44  				ForceNew: true, // TODO make this editable
    45  			},
    46  			"memory_size": &schema.Schema{
    47  				Type:     schema.TypeInt,
    48  				Optional: true,
    49  				Default:  128,
    50  				ForceNew: true, // TODO make this editable
    51  			},
    52  			"role": &schema.Schema{
    53  				Type:     schema.TypeString,
    54  				Required: true,
    55  				ForceNew: true, // TODO make this editable
    56  			},
    57  			"runtime": &schema.Schema{
    58  				Type:     schema.TypeString,
    59  				Optional: true,
    60  				ForceNew: true,
    61  				Default:  "nodejs",
    62  			},
    63  			"timeout": &schema.Schema{
    64  				Type:     schema.TypeInt,
    65  				Optional: true,
    66  				Default:  3,
    67  				ForceNew: true, // TODO make this editable
    68  			},
    69  			"arn": &schema.Schema{
    70  				Type:     schema.TypeString,
    71  				Computed: true,
    72  			},
    73  			"last_modified": &schema.Schema{
    74  				Type:     schema.TypeString,
    75  				Computed: true,
    76  			},
    77  			"source_code_hash": &schema.Schema{
    78  				Type:     schema.TypeString,
    79  				Computed: true,
    80  				ForceNew: true,
    81  			},
    82  		},
    83  	}
    84  }
    85  
    86  // resourceAwsLambdaFunction maps to:
    87  // CreateFunction in the API / SDK
    88  func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) error {
    89  	conn := meta.(*AWSClient).lambdaconn
    90  
    91  	functionName := d.Get("function_name").(string)
    92  	iamRole := d.Get("role").(string)
    93  
    94  	log.Printf("[DEBUG] Creating Lambda Function %s with role %s", functionName, iamRole)
    95  
    96  	filename, err := homedir.Expand(d.Get("filename").(string))
    97  	if err != nil {
    98  		return err
    99  	}
   100  	zipfile, err := ioutil.ReadFile(filename)
   101  	if err != nil {
   102  		return err
   103  	}
   104  	d.Set("source_code_hash", sha256.Sum256(zipfile))
   105  
   106  	log.Printf("[DEBUG] ")
   107  
   108  	params := &lambda.CreateFunctionInput{
   109  		Code: &lambda.FunctionCode{
   110  			ZipFile: zipfile,
   111  		},
   112  		Description:  aws.String(d.Get("description").(string)),
   113  		FunctionName: aws.String(functionName),
   114  		Handler:      aws.String(d.Get("handler").(string)),
   115  		MemorySize:   aws.Int64(int64(d.Get("memory_size").(int))),
   116  		Role:         aws.String(iamRole),
   117  		Runtime:      aws.String(d.Get("runtime").(string)),
   118  		Timeout:      aws.Int64(int64(d.Get("timeout").(int))),
   119  	}
   120  
   121  	for i := 0; i < 5; i++ {
   122  		_, err = conn.CreateFunction(params)
   123  		if awsErr, ok := err.(awserr.Error); ok {
   124  
   125  			// IAM profiles can take ~10 seconds to propagate in AWS:
   126  			//  http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#launch-instance-with-role-console
   127  			// Error creating Lambda function: InvalidParameterValueException: The role defined for the task cannot be assumed by Lambda.
   128  			if awsErr.Code() == "InvalidParameterValueException" && strings.Contains(awsErr.Message(), "The role defined for the task cannot be assumed by Lambda.") {
   129  				log.Printf("[DEBUG] Invalid IAM Instance Profile referenced, retrying...")
   130  				time.Sleep(2 * time.Second)
   131  				continue
   132  			}
   133  		}
   134  		break
   135  	}
   136  	if err != nil {
   137  		return fmt.Errorf("Error creating Lambda function: %s", err)
   138  	}
   139  
   140  	d.SetId(d.Get("function_name").(string))
   141  
   142  	return resourceAwsLambdaFunctionRead(d, meta)
   143  }
   144  
   145  // resourceAwsLambdaFunctionRead maps to:
   146  // GetFunction in the API / SDK
   147  func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) error {
   148  	conn := meta.(*AWSClient).lambdaconn
   149  
   150  	log.Printf("[DEBUG] Fetching Lambda Function: %s", d.Id())
   151  
   152  	params := &lambda.GetFunctionInput{
   153  		FunctionName: aws.String(d.Get("function_name").(string)),
   154  	}
   155  
   156  	getFunctionOutput, err := conn.GetFunction(params)
   157  	if err != nil {
   158  		return err
   159  	}
   160  
   161  	// getFunctionOutput.Code.Location is a pre-signed URL pointing at the zip
   162  	// file that we uploaded when we created the resource. You can use it to
   163  	// download the code from AWS. The other part is
   164  	// getFunctionOutput.Configuration which holds metadata.
   165  
   166  	function := getFunctionOutput.Configuration
   167  	// TODO error checking / handling on the Set() calls.
   168  	d.Set("arn", function.FunctionArn)
   169  	d.Set("description", function.Description)
   170  	d.Set("handler", function.Handler)
   171  	d.Set("memory_size", function.MemorySize)
   172  	d.Set("last_modified", function.LastModified)
   173  	d.Set("role", function.Role)
   174  	d.Set("runtime", function.Runtime)
   175  	d.Set("timeout", function.Timeout)
   176  
   177  	return nil
   178  }
   179  
   180  // resourceAwsLambdaFunction maps to:
   181  // DeleteFunction in the API / SDK
   182  func resourceAwsLambdaFunctionDelete(d *schema.ResourceData, meta interface{}) error {
   183  	conn := meta.(*AWSClient).lambdaconn
   184  
   185  	log.Printf("[INFO] Deleting Lambda Function: %s", d.Id())
   186  
   187  	params := &lambda.DeleteFunctionInput{
   188  		FunctionName: aws.String(d.Get("function_name").(string)),
   189  	}
   190  
   191  	_, err := conn.DeleteFunction(params)
   192  	if err != nil {
   193  		return fmt.Errorf("Error deleting Lambda Function: %s", err)
   194  	}
   195  
   196  	d.SetId("")
   197  
   198  	return nil
   199  }
   200  
   201  // resourceAwsLambdaFunctionUpdate maps to:
   202  // UpdateFunctionCode in the API / SDK
   203  func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) error {
   204  	// conn := meta.(*AWSClient).lambdaconn
   205  
   206  	return nil
   207  }