// Report logs the error to the Logger. func (h *LogReporter) Report(ctx context.Context, err error) error { switch err := err.(type) { case *Error: var line *BacktraceLine if len(err.Backtrace) > 0 { line = err.Backtrace[0] } else { line = &BacktraceLine{ File: "unknown", Line: 0, } } logger.Error(ctx, "", "error", fmt.Sprintf(`"%v"`, err), "line", line.Line, "file", line.File) default: logger.Error(ctx, "", "error", fmt.Sprintf(`"%v"`, err)) } return nil }
// Handle handles a single sqs.Message to perform the provisioning. func (c *CustomResourceProvisioner) Handle(ctx context.Context, message *sqs.Message) error { var m Message err := json.Unmarshal([]byte(*message.Body), &m) if err != nil { return fmt.Errorf("error unmarshalling sqs message body: %v", err) } var req customresources.Request err = json.Unmarshal([]byte(m.Message), &req) if err != nil { return fmt.Errorf("error unmarshalling to cloudformation request: %v", err) } logger.Info(ctx, "cloudformation.provision.request", "request_id", req.RequestId, "stack_id", req.StackId, "request_type", req.RequestType, "resource_type", req.ResourceType, "logical_resource_id", req.LogicalResourceId, "physical_resource_id", req.PhysicalResourceId, ) resp := customresources.NewResponseFromRequest(req) // CloudFormation is weird. PhysicalResourceId is required when creating // a resource, but if the creation fails, how would we have a physical // resource id? In cases where a Create request fails, we set the // physical resource id to `failed/Create`. When a delete request comes // in to delete that resource, we just send back a SUCCESS response so // CloudFormation is happy. if req.RequestType == customresources.Delete && req.PhysicalResourceId == fmt.Sprintf("failed/%s", customresources.Create) { resp.PhysicalResourceId = req.PhysicalResourceId } else { resp.PhysicalResourceId, resp.Data, err = c.provision(ctx, m, req) } // Allow provisioners to just return "" to indicate that the physical // resource id did not change. if resp.PhysicalResourceId == "" && req.PhysicalResourceId != "" { resp.PhysicalResourceId = req.PhysicalResourceId } switch err { case nil: resp.Status = customresources.StatusSuccess logger.Info(ctx, "cloudformation.provision.success", "request_id", req.RequestId, "stack_id", req.StackId, "physical_resource_id", resp.PhysicalResourceId, ) default: // A physical resource id is required, so if a Create request // fails, and there's no physical resource id, CloudFormation // will only say `Invalid PhysicalResourceId` in the status // Reason instead of the actual error that caused the Create to // fail. if req.RequestType == customresources.Create && resp.PhysicalResourceId == "" { resp.PhysicalResourceId = fmt.Sprintf("failed/%s", req.RequestType) } resp.Status = customresources.StatusFailed resp.Reason = err.Error() logger.Error(ctx, "cloudformation.provision.error", "request_id", req.RequestId, "stack_id", req.StackId, "err", err.Error(), ) } return c.sendResponse(req, resp) }