Example #1
0
// 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
}
Example #2
0
// 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)
}