2015-06-01 18:33:22 +02:00
|
|
|
package aws
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/sha256"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2015-06-09 21:12:47 +02:00
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
|
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
|
|
|
"github.com/aws/aws-sdk-go/service/lambda"
|
2015-06-09 21:27:40 +02:00
|
|
|
"github.com/mitchellh/go-homedir"
|
2015-06-01 18:33:22 +02:00
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/helper/schema"
|
|
|
|
)
|
|
|
|
|
|
|
|
func resourceAwsLambdaFunction() *schema.Resource {
|
|
|
|
return &schema.Resource{
|
|
|
|
Create: resourceAwsLambdaFunctionCreate,
|
|
|
|
Read: resourceAwsLambdaFunctionRead,
|
|
|
|
Update: resourceAwsLambdaFunctionUpdate,
|
|
|
|
Delete: resourceAwsLambdaFunctionDelete,
|
|
|
|
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
|
|
"filename": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
"description": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
ForceNew: true, // TODO make this editable
|
|
|
|
},
|
|
|
|
"function_name": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
ForceNew: true,
|
|
|
|
},
|
|
|
|
"handler": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
ForceNew: true, // TODO make this editable
|
|
|
|
},
|
|
|
|
"memory_size": &schema.Schema{
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Optional: true,
|
|
|
|
Default: 128,
|
|
|
|
ForceNew: true, // TODO make this editable
|
|
|
|
},
|
|
|
|
"role": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
ForceNew: true, // TODO make this editable
|
|
|
|
},
|
|
|
|
"runtime": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
ForceNew: true,
|
|
|
|
Default: "nodejs",
|
|
|
|
},
|
|
|
|
"timeout": &schema.Schema{
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Optional: true,
|
|
|
|
Default: 3,
|
|
|
|
ForceNew: true, // TODO make this editable
|
|
|
|
},
|
|
|
|
"arn": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"last_modified": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"source_code_hash": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Computed: true,
|
|
|
|
ForceNew: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// resourceAwsLambdaFunction maps to:
|
|
|
|
// CreateFunction in the API / SDK
|
|
|
|
func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) error {
|
|
|
|
conn := meta.(*AWSClient).lambdaconn
|
|
|
|
|
|
|
|
functionName := d.Get("function_name").(string)
|
|
|
|
iamRole := d.Get("role").(string)
|
|
|
|
|
|
|
|
log.Printf("[DEBUG] Creating Lambda Function %s with role %s", functionName, iamRole)
|
|
|
|
|
2015-06-09 21:27:40 +02:00
|
|
|
filename, err := homedir.Expand(d.Get("filename").(string))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
zipfile, err := ioutil.ReadFile(filename)
|
2015-06-01 18:33:22 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
d.Set("source_code_hash", sha256.Sum256(zipfile))
|
|
|
|
|
|
|
|
log.Printf("[DEBUG] ")
|
|
|
|
|
|
|
|
params := &lambda.CreateFunctionInput{
|
|
|
|
Code: &lambda.FunctionCode{
|
|
|
|
ZipFile: zipfile,
|
|
|
|
},
|
|
|
|
Description: aws.String(d.Get("description").(string)),
|
|
|
|
FunctionName: aws.String(functionName),
|
|
|
|
Handler: aws.String(d.Get("handler").(string)),
|
2015-07-28 22:29:46 +02:00
|
|
|
MemorySize: aws.Int64(int64(d.Get("memory_size").(int))),
|
2015-06-01 18:33:22 +02:00
|
|
|
Role: aws.String(iamRole),
|
|
|
|
Runtime: aws.String(d.Get("runtime").(string)),
|
2015-07-28 22:29:46 +02:00
|
|
|
Timeout: aws.Int64(int64(d.Get("timeout").(int))),
|
2015-06-01 18:33:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < 5; i++ {
|
|
|
|
_, err = conn.CreateFunction(params)
|
|
|
|
if awsErr, ok := err.(awserr.Error); ok {
|
|
|
|
|
|
|
|
// IAM profiles can take ~10 seconds to propagate in AWS:
|
|
|
|
// http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#launch-instance-with-role-console
|
|
|
|
// Error creating Lambda function: InvalidParameterValueException: The role defined for the task cannot be assumed by Lambda.
|
|
|
|
if awsErr.Code() == "InvalidParameterValueException" && strings.Contains(awsErr.Message(), "The role defined for the task cannot be assumed by Lambda.") {
|
|
|
|
log.Printf("[DEBUG] Invalid IAM Instance Profile referenced, retrying...")
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error creating Lambda function: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
d.SetId(d.Get("function_name").(string))
|
|
|
|
|
|
|
|
return resourceAwsLambdaFunctionRead(d, meta)
|
|
|
|
}
|
|
|
|
|
|
|
|
// resourceAwsLambdaFunctionRead maps to:
|
|
|
|
// GetFunction in the API / SDK
|
|
|
|
func resourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) error {
|
|
|
|
conn := meta.(*AWSClient).lambdaconn
|
|
|
|
|
|
|
|
log.Printf("[DEBUG] Fetching Lambda Function: %s", d.Id())
|
|
|
|
|
|
|
|
params := &lambda.GetFunctionInput{
|
|
|
|
FunctionName: aws.String(d.Get("function_name").(string)),
|
|
|
|
}
|
|
|
|
|
|
|
|
getFunctionOutput, err := conn.GetFunction(params)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// getFunctionOutput.Code.Location is a pre-signed URL pointing at the zip
|
|
|
|
// file that we uploaded when we created the resource. You can use it to
|
|
|
|
// download the code from AWS. The other part is
|
|
|
|
// getFunctionOutput.Configuration which holds metadata.
|
|
|
|
|
|
|
|
function := getFunctionOutput.Configuration
|
|
|
|
// TODO error checking / handling on the Set() calls.
|
|
|
|
d.Set("arn", function.FunctionARN)
|
|
|
|
d.Set("description", function.Description)
|
|
|
|
d.Set("handler", function.Handler)
|
|
|
|
d.Set("memory_size", function.MemorySize)
|
|
|
|
d.Set("last_modified", function.LastModified)
|
|
|
|
d.Set("role", function.Role)
|
|
|
|
d.Set("runtime", function.Runtime)
|
|
|
|
d.Set("timeout", function.Timeout)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// resourceAwsLambdaFunction maps to:
|
|
|
|
// DeleteFunction in the API / SDK
|
|
|
|
func resourceAwsLambdaFunctionDelete(d *schema.ResourceData, meta interface{}) error {
|
|
|
|
conn := meta.(*AWSClient).lambdaconn
|
|
|
|
|
|
|
|
log.Printf("[INFO] Deleting Lambda Function: %s", d.Id())
|
|
|
|
|
|
|
|
params := &lambda.DeleteFunctionInput{
|
|
|
|
FunctionName: aws.String(d.Get("function_name").(string)),
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := conn.DeleteFunction(params)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error deleting Lambda Function: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
d.SetId("")
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// resourceAwsLambdaFunctionUpdate maps to:
|
|
|
|
// UpdateFunctionCode in the API / SDK
|
|
|
|
func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) error {
|
|
|
|
// conn := meta.(*AWSClient).lambdaconn
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|