diff --git a/docs/resources/cloud-watch-logs-log-group.md b/docs/resources/cloud-watch-logs-log-group.md index a9d24a0d..a105b73e 100644 --- a/docs/resources/cloud-watch-logs-log-group.md +++ b/docs/resources/cloud-watch-logs-log-group.md @@ -11,8 +11,17 @@ generated: true CloudWatchLogsLogGroup ``` +## Properties +- `CreatedTime`: The creation time of the log group in unix timestamp format +- `CreationTime`: The creation time of the log group in RFC3339 format +- `LastEvent`: The last event time of the log group in RFC3339 format +- `Name`: The name of the log group +- `RetentionInDays`: The number of days to retain log events in the log group +- `tag::`: This resource has tags with property `Tags`. These are key/value pairs that are + added as their own property with the prefix of `tag:` (e.g. [tag:example: "value"]) + !!! note - Using Properties Properties are what [Filters](../config-filtering.md) are written against in your configuration. You use the property names to write filters for what you want to **keep** and omit from the nuke process. diff --git a/resources/cloudwatchlogs-loggroups.go b/resources/cloudwatchlogs-loggroup.go similarity index 62% rename from resources/cloudwatchlogs-loggroups.go rename to resources/cloudwatchlogs-loggroup.go index eae192be..c4cfcb69 100644 --- a/resources/cloudwatchlogs-loggroups.go +++ b/resources/cloudwatchlogs-loggroup.go @@ -5,9 +5,9 @@ import ( "strings" "time" + "github.com/gotidy/ptr" "go.uber.org/ratelimit" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/cloudwatchlogs" "github.com/ekristen/libnuke/pkg/registry" @@ -46,7 +46,7 @@ func (l *CloudWatchLogsLogGroupLister) List(_ context.Context, o interface{}) ([ streamRl := ratelimit.New(15) params := &cloudwatchlogs.DescribeLogGroupsInput{ - Limit: aws.Int64(50), + Limit: ptr.Int64(50), } for { @@ -72,9 +72,9 @@ func (l *CloudWatchLogsLogGroupLister) List(_ context.Context, o interface{}) ([ // get last event ingestion time lsResp, err := svc.DescribeLogStreams(&cloudwatchlogs.DescribeLogStreamsInput{ LogGroupName: logGroup.LogGroupName, - OrderBy: aws.String("LastEventTime"), - Limit: aws.Int64(1), - Descending: aws.Bool(true), + OrderBy: ptr.String("LastEventTime"), + Limit: ptr.Int64(1), + Descending: ptr.Bool(true), }) if err != nil { return nil, err @@ -87,14 +87,21 @@ func (l *CloudWatchLogsLogGroupLister) List(_ context.Context, o interface{}) ([ lastEvent = time.Unix(*logGroup.CreationTime/1000, 0) } + var retentionInDays int64 + if logGroup.RetentionInDays != nil { + retentionInDays = ptr.ToInt64(logGroup.RetentionInDays) + } + resources = append(resources, &CloudWatchLogsLogGroup{ - svc: svc, - logGroup: logGroup, - lastEvent: lastEvent.Format(time.RFC3339), - tags: tagResp.Tags, + svc: svc, + Name: logGroup.LogGroupName, + CreatedTime: logGroup.CreationTime, + CreationTime: ptr.Time(time.Unix(*logGroup.CreationTime/1000, 0).UTC()), + LastEvent: ptr.Time(lastEvent), // TODO(v4): convert to UTC + RetentionInDays: retentionInDays, + Tags: tagResp.Tags, }) } - if output.NextToken == nil { break } @@ -106,32 +113,28 @@ func (l *CloudWatchLogsLogGroupLister) List(_ context.Context, o interface{}) ([ } type CloudWatchLogsLogGroup struct { - svc *cloudwatchlogs.CloudWatchLogs - logGroup *cloudwatchlogs.LogGroup - lastEvent string - tags map[string]*string + svc *cloudwatchlogs.CloudWatchLogs + Name *string `description:"The name of the log group"` + CreatedTime *int64 `description:"The creation time of the log group in unix timestamp format"` + CreationTime *time.Time `description:"The creation time of the log group in RFC3339 format"` + LastEvent *time.Time `description:"The last event time of the log group in RFC3339 format"` + RetentionInDays int64 `description:"The number of days to retain log events in the log group"` + Tags map[string]*string } -func (f *CloudWatchLogsLogGroup) Remove(_ context.Context) error { - _, err := f.svc.DeleteLogGroup(&cloudwatchlogs.DeleteLogGroupInput{ - LogGroupName: f.logGroup.LogGroupName, +func (r *CloudWatchLogsLogGroup) Remove(_ context.Context) error { + _, err := r.svc.DeleteLogGroup(&cloudwatchlogs.DeleteLogGroupInput{ + LogGroupName: r.Name, }) return err } -func (f *CloudWatchLogsLogGroup) String() string { - return *f.logGroup.LogGroupName +func (r *CloudWatchLogsLogGroup) String() string { + return *r.Name } -func (f *CloudWatchLogsLogGroup) Properties() types.Properties { - properties := types.NewProperties(). - Set("logGroupName", f.logGroup.LogGroupName). - Set("CreatedTime", f.logGroup.CreationTime). - Set("LastEvent", f.lastEvent) - - for k, v := range f.tags { - properties.SetTag(&k, v) - } - return properties +func (r *CloudWatchLogsLogGroup) Properties() types.Properties { + return types.NewPropertiesFromStruct(r). + Set("logGroupName", r.Name) // TODO(v4): remove this property } diff --git a/resources/cloudwatchlogs-loggroup_test.go b/resources/cloudwatchlogs-loggroup_test.go new file mode 100644 index 00000000..e2d2e669 --- /dev/null +++ b/resources/cloudwatchlogs-loggroup_test.go @@ -0,0 +1,34 @@ +package resources + +import ( + "strconv" + "testing" + "time" + + "github.com/gotidy/ptr" + "github.com/stretchr/testify/assert" +) + +func TestCloudWatchLogsLogGroupProperties(t *testing.T) { + now := time.Now().UTC() + + r := &CloudWatchLogsLogGroup{ + Name: ptr.String("test-log-group"), + CreatedTime: ptr.Int64(now.Unix()), + CreationTime: ptr.Time(now), + LastEvent: ptr.Time(now), + RetentionInDays: 7, + Tags: map[string]*string{ + "Environment": ptr.String("production"), + }, + } + + properties := r.Properties() + assert.Equal(t, properties.Get("logGroupName"), "test-log-group") + assert.Equal(t, properties.Get("Name"), "test-log-group") + assert.Equal(t, properties.Get("CreatedTime"), strconv.Itoa(int(now.Unix()))) + assert.Equal(t, properties.Get("CreationTime"), now.Format(time.RFC3339)) + assert.Equal(t, properties.Get("LastEvent"), now.Format(time.RFC3339)) + assert.Equal(t, properties.Get("RetentionInDays"), "7") + assert.Equal(t, properties.Get("tag:Environment"), "production") +}