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