-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(logwriter): trigger on update (#319)
It is common practice to iteratively adjust parameters in the logwriter stack and refine filters through trial and error. Previously, log discovery and subscription would only run once our scheduler fired. This commit additionally ensures we manually trigger the lambda on any parameter change to our CloudFormation stack. The commit adds: - a custom resource to our CloudFormation logwriter stack which embeds all parameters. Any change to our input parameters will generate a CloudFormation event which triggers the subscriber Lambda function. - a handler to the subscriber Lambda function which processes CloudFormation events. On stack updates, we will initiate a discovery request. We do not need to do any handling on install, since the scheduler will fire on first time install. - a step to our integration tests which updates the stack to exercise the new functionality. IAM permissions were added to account for new behavior. CloudFormation triggers are notoriously fussy. Our lambda must respond promptly, or risk holding up the CloudFormation process for an inordinately long time. To avoid this fate, this commit: - is liberal in what it accepts as a CloudFormation event. Any payload that has sufficient metadata to generate a response will be interpreted as being valid. This ensures we are future proof to any schema extensions. - immediately acknowledges the CloudFormation event before initiating discovery in order to not hold up install / update / delete process.
- Loading branch information
Showing
11 changed files
with
401 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package subscriber | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/aws/aws-lambda-go/cfn" | ||
"github.com/aws/aws-lambda-go/lambdacontext" | ||
"github.com/go-logr/logr" | ||
) | ||
|
||
var ( | ||
ErrMalformedEvent = errors.New("malformed cloudformation event") | ||
) | ||
|
||
// CloudFormationEvent adds a field which is not declared in cloudformation package | ||
type CloudFormationEvent struct { | ||
*cfn.Event | ||
} | ||
|
||
// UnmarshalJSON provides a custom unmarshaller that allows unknown fields. | ||
// It is critical that we respond to any CloudFormation event, otherwise stack | ||
// install, updates and deletes will stall. In order to protect ourselves | ||
// against unexpected fields, we succeed unmarshalling so long as we have the | ||
// necessary elements to form a response. | ||
func (c *CloudFormationEvent) UnmarshalJSON(data []byte) error { | ||
if err := json.Unmarshal(data, &c.Event); err != nil { | ||
return err | ||
} | ||
|
||
switch { | ||
case c.RequestID == "": | ||
case c.ResponseURL == "": | ||
case c.LogicalResourceID == "": | ||
case c.StackID == "": | ||
default: | ||
return nil | ||
} | ||
|
||
return fmt.Errorf("not a cloudformation event") | ||
} | ||
|
||
func makeStrSlice(item any) ([]*string, error) { | ||
vs, ok := item.([]any) | ||
if !ok { | ||
return nil, fmt.Errorf("failed to cast %v to slice", item) | ||
} | ||
var ret []*string | ||
for _, v := range vs { | ||
s, ok := v.(string) | ||
if !ok { | ||
return nil, fmt.Errorf("failed to cast %v to string", v) | ||
} | ||
ret = append(ret, &s) | ||
} | ||
return ret, nil | ||
} | ||
|
||
// HandleCloudFormation triggers discovery on CloudFormation stack updates | ||
func (h *Handler) HandleCloudFormation(ctx context.Context, ev *CloudFormationEvent) (*Response, error) { | ||
logger := logr.FromContextOrDiscard(ctx) | ||
|
||
if ev == nil { | ||
return &Response{}, nil | ||
} | ||
|
||
logger.V(3).Info("handling cloudformation event", "requestType", ev.RequestType) | ||
|
||
response := cfn.NewResponse(ev.Event) | ||
response.PhysicalResourceID = lambdacontext.LogStreamName | ||
response.Status = cfn.StatusSuccess | ||
err := response.Send() | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to send cloudformation response: %w", err) | ||
} | ||
|
||
if ev.RequestType == cfn.RequestUpdate { | ||
var req DiscoveryRequest | ||
if req.LogGroupNamePatterns, err = makeStrSlice(ev.ResourceProperties["LogGroupNamePatterns"]); err != nil { | ||
return nil, fmt.Errorf("failed to extract logGroupNamePatterns: %w", err) | ||
} | ||
if req.LogGroupNamePrefixes, err = makeStrSlice(ev.ResourceProperties["LogGroupNamePrefixes"]); err != nil { | ||
return nil, fmt.Errorf("failed to extract logGroupNamePrefixes: %w", err) | ||
} | ||
return h.HandleDiscoveryRequest(ctx, &req) | ||
} | ||
|
||
return &Response{}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.