github.com/erriapo/terraform@v0.6.12-0.20160203182612-0340ea72354f/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  	"time"
     9  
    10  	"github.com/aws/aws-sdk-go/aws"
    11  	"github.com/aws/aws-sdk-go/aws/awserr"
    12  	"github.com/aws/aws-sdk-go/service/lambda"
    13  	"github.com/mitchellh/go-homedir"
    14  
    15  	"errors"
    16  
    17  	"github.com/hashicorp/terraform/helper/resource"
    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  	// IAM profiles can take ~10 seconds to propagate in AWS:
   153  	//  http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#launch-instance-with-role-console
   154  	// Error creating Lambda function: InvalidParameterValueException: The role defined for the task cannot be assumed by Lambda.
   155  	err := resource.Retry(1*time.Minute, func() error {
   156  		_, err := conn.CreateFunction(params)
   157  		if err != nil {
   158  			if awserr, ok := err.(awserr.Error); ok {
   159  				if awserr.Code() == "InvalidParameterValueException" {
   160  					// Retryable
   161  					return awserr
   162  				}
   163  			}
   164  			// Not retryable
   165  			return resource.RetryError{Err: err}
   166  		}
   167  		// No error
   168  		return nil
   169  	})
   170  	if err != nil {
   171  		return fmt.Errorf("Error creating Lambda function: %s", err)
   172  	}
   173  
   174  	d.SetId(d.Get("function_name").(string))
   175  
   176  	return resourceAwsLambdaFunctionRead(d, meta)
   177  }
   178  
   179  // resourceAwsLambdaFunctionRead maps to:
   180  // GetFunction in the API / SDK
   181  func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) error {
   182  	conn := meta.(*AWSClient).lambdaconn
   183  
   184  	log.Printf("[DEBUG] Fetching Lambda Function: %s", d.Id())
   185  
   186  	params := &lambda.GetFunctionInput{
   187  		FunctionName: aws.String(d.Get("function_name").(string)),
   188  	}
   189  
   190  	getFunctionOutput, err := conn.GetFunction(params)
   191  	if err != nil {
   192  		return err
   193  	}
   194  
   195  	// getFunctionOutput.Code.Location is a pre-signed URL pointing at the zip
   196  	// file that we uploaded when we created the resource. You can use it to
   197  	// download the code from AWS. The other part is
   198  	// getFunctionOutput.Configuration which holds metadata.
   199  
   200  	function := getFunctionOutput.Configuration
   201  	// TODO error checking / handling on the Set() calls.
   202  	d.Set("arn", function.FunctionArn)
   203  	d.Set("description", function.Description)
   204  	d.Set("handler", function.Handler)
   205  	d.Set("memory_size", function.MemorySize)
   206  	d.Set("last_modified", function.LastModified)
   207  	d.Set("role", function.Role)
   208  	d.Set("runtime", function.Runtime)
   209  	d.Set("timeout", function.Timeout)
   210  
   211  	return nil
   212  }
   213  
   214  // resourceAwsLambdaFunction maps to:
   215  // DeleteFunction in the API / SDK
   216  func resourceAwsLambdaFunctionDelete(d *schema.ResourceData, meta interface{}) error {
   217  	conn := meta.(*AWSClient).lambdaconn
   218  
   219  	log.Printf("[INFO] Deleting Lambda Function: %s", d.Id())
   220  
   221  	params := &lambda.DeleteFunctionInput{
   222  		FunctionName: aws.String(d.Get("function_name").(string)),
   223  	}
   224  
   225  	_, err := conn.DeleteFunction(params)
   226  	if err != nil {
   227  		return fmt.Errorf("Error deleting Lambda Function: %s", err)
   228  	}
   229  
   230  	d.SetId("")
   231  
   232  	return nil
   233  }
   234  
   235  // resourceAwsLambdaFunctionUpdate maps to:
   236  // UpdateFunctionCode in the API / SDK
   237  func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) error {
   238  	// conn := meta.(*AWSClient).lambdaconn
   239  
   240  	return nil
   241  }