func (infra *Infrastructure) createLambdaFunction(svc *lambda.Lambda, roleArn string, payload []byte) error { function, err := svc.CreateFunction(&lambda.CreateFunctionInput{ Code: &lambda.FunctionCode{ ZipFile: payload, }, FunctionName: aws.String("goad"), Handler: aws.String("index.handler"), Role: aws.String(roleArn), Runtime: aws.String("nodejs"), MemorySize: aws.Int64(1536), Publish: aws.Bool(true), Timeout: aws.Int64(300), }) if err != nil { if awsErr, ok := err.(awserr.Error); ok { // Calling this function too soon after creating the role might // fail, so we should retry after a little while. // TODO: limit the number of retries. if awsErr.Code() == "InvalidParameterValueException" { time.Sleep(time.Second) return infra.createLambdaFunction(svc, roleArn, payload) } } return err } return createLambdaAlias(svc, function.Version) }
func lambdaPermissionExists(rs *terraform.ResourceState, conn *lambda.Lambda) (*LambdaPolicyStatement, error) { params := &lambda.GetPolicyInput{ FunctionName: aws.String(rs.Primary.Attributes["function_name"]), } if v, ok := rs.Primary.Attributes["qualifier"]; ok { params.Qualifier = aws.String(v) } resp, err := conn.GetPolicy(params) if err != nil { return nil, fmt.Errorf("Lambda policy not found: %q", err) } if resp.Policy == nil { return nil, fmt.Errorf("Received Lambda policy is empty") } policyInBytes := []byte(*resp.Policy) policy := LambdaPolicy{} err = json.Unmarshal(policyInBytes, &policy) if err != nil { return nil, fmt.Errorf("Error unmarshalling Lambda policy: %s", err) } return findLambdaPolicyStatementById(&policy, rs.Primary.ID) }
func createLambdaAlias(svc *lambda.Lambda, functionVersion *string) error { _, err := svc.CreateAlias(&lambda.CreateAliasInput{ FunctionName: aws.String("goad"), FunctionVersion: functionVersion, Name: aws.String(version.LambdaVersion()), }) return err }
func (infra *Infrastructure) updateLambdaFunction(svc *lambda.Lambda, roleArn string, payload []byte) error { function, err := svc.UpdateFunctionCode(&lambda.UpdateFunctionCodeInput{ ZipFile: payload, FunctionName: aws.String("goad"), Publish: aws.Bool(true), }) if err != nil { return err } return createLambdaAlias(svc, function.Version) }
func listVersionsByFunctionPages(c *lambda.Lambda, input *lambda.ListVersionsByFunctionInput, fn func(p *lambda.ListVersionsByFunctionOutput, lastPage bool) bool) error { for { page, err := c.ListVersionsByFunction(input) if err != nil { return err } lastPage := page.NextMarker == nil shouldContinue := fn(page, lastPage) if !shouldContinue || lastPage { break } } return nil }
func lambdaExists(svc *lambda.Lambda) (bool, error) { _, err := svc.GetFunction(&lambda.GetFunctionInput{ FunctionName: aws.String("goad"), }) if err != nil { if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "ResourceNotFoundException" { return false, nil } } return false, err } return true, nil }
func isLambdaPermissionGone(rs *terraform.ResourceState, conn *lambda.Lambda) error { params := &lambda.GetPolicyInput{ FunctionName: aws.String(rs.Primary.Attributes["function_name"]), } if v, ok := rs.Primary.Attributes["qualifier"]; ok { params.Qualifier = aws.String(v) } resp, err := conn.GetPolicy(params) if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "ResourceNotFoundException" { // no policy found => all statements deleted return nil } } if err != nil { return fmt.Errorf("Unexpected error when checking existence of Lambda permission: %s\n%s", rs.Primary.ID, err) } policyInBytes := []byte(*resp.Policy) policy := LambdaPolicy{} err = json.Unmarshal(policyInBytes, &policy) if err != nil { return fmt.Errorf("Error unmarshalling Lambda policy (%s): %s", *resp.Policy, err) } state, err := findLambdaPolicyStatementById(&policy, rs.Primary.ID) if err != nil { // statement not found => deleted return nil } return fmt.Errorf("Policy statement expected to be gone (%s):\n%s", rs.Primary.ID, *state) }
func createLambdaFunction(l *lambda.Lambda, code []byte, runtime, role, name, handler string, timeout int) error { func_input := &lambda.CreateFunctionInput{ Code: &lambda.FunctionCode{ZipFile: code}, Runtime: aws.String(runtime), Role: aws.String(role), FunctionName: aws.String(name), Handler: aws.String(handler), Timeout: aws.Int64(int64(timeout)), } resp, err := l.CreateFunction(func_input) if err != nil { if err.(awserr.Error).Code() == "ResourceConflictException" { log.Println("Function already exists, trying to update code") input := &lambda.UpdateFunctionCodeInput{ FunctionName: aws.String(name), ZipFile: code, } resp, err = l.UpdateFunctionCode(input) if err != nil { log.Println("Could not update function code", err) return err } configInput := &lambda.UpdateFunctionConfigurationInput{ FunctionName: aws.String(name), Handler: aws.String(handler), Timeout: aws.Int64(int64(timeout)), } resp, err = l.UpdateFunctionConfiguration(configInput) if err != nil { log.Println("Could not update function configuration", err) return err } } else { return err } } log.Println(resp) return nil }
//Returns a result and a debug channels. The channels are closed on test run finalization func runOnLambda(l *lambda.Lambda, cw *cloudwatchlogs.CloudWatchLogs, test *util.TestDescription) (<-chan string, <-chan string) { result := make(chan string, 1) debug := make(chan string, 1) go func() { defer close(result) defer close(debug) name := test.Name debug <- "Getting old log" old_invocation_log, err := getLog(cw, name) if err != nil { old_invocation_log = "" } payload, _ := json.Marshal(test.Event) invoke_input := &lambda.InvokeInput{ FunctionName: aws.String(name), InvocationType: aws.String("Event"), Payload: payload, } debug <- "Enqueuing task" _, err = l.Invoke(invoke_input) if err != nil { debug <- fmt.Sprintf("Error invoking function %s ", err) return } timeout := time.Duration(test.Timeout) * time.Second debug <- "Waiting for task" now := time.Now() elapsed := time.After(timeout) ticker := time.NewTicker(3 * time.Second) defer ticker.Stop() log := "" completed := false requestId := "" logGetter := func() (string, error) { return getLog(cw, name) } // waiting for test.Timeout or for the full log whichever occurs first logWaitLoop: for { select { case <-elapsed: break logWaitLoop case <-ticker.C: log, requestId, completed, err = getLogAndDetectRequestComplete(logGetter, old_invocation_log, requestId) if err != nil { debug <- fmt.Sprintf("Error getting log %s ", err) return } if completed { break logWaitLoop } } } if !completed { log, requestId, completed, err = getLogAndDetectRequestComplete(logGetter, old_invocation_log, requestId) if err != nil { debug <- fmt.Sprintf("Error getting log %s ", err) return } if !completed { if requestId != "" { debug <- fmt.Sprintf("Request Id: %s", requestId) } debug <- time.Now().Sub(now).String() logLines := strings.Split(log, "\n") switch len(logLines) { case 0: debug <- "Log for current test run is empty" case 1: debug <- fmt.Sprintf("Log does not contain entries for current test run:\n%s", logLines[0]) default: debug <- fmt.Sprintf("Log does not contain entries for current test run:\n%s\n...\n%s", logLines[0], logLines[len(logLines)-1]) } return } } debug <- fmt.Sprintf("Request Id: %s", requestId) final, err := cleanLambda(log) if err != nil { debug <- fmt.Sprintf("Error cleaning log %s", err) return } result <- final }() return result, debug }