From 658da80e235b8fd31c44057e8165b86057ca8dc7 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Sun, 11 Aug 2024 11:27:18 +0200 Subject: [PATCH] =?UTF-8?q?=E2=AD=90=EF=B8=8F=20aws=20rds=20pending=20main?= =?UTF-8?q?tainance=20actions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- providers/aws/resources/aws.lr | 22 +++ providers/aws/resources/aws.lr.go | 179 +++++++++++++++++++ providers/aws/resources/aws.lr.manifest.yaml | 18 ++ providers/aws/resources/aws_rds.go | 131 ++++++++++++++ 4 files changed, 350 insertions(+) diff --git a/providers/aws/resources/aws.lr b/providers/aws/resources/aws.lr index b49bf07341..93991bb4b8 100644 --- a/providers/aws/resources/aws.lr +++ b/providers/aws/resources/aws.lr @@ -2022,6 +2022,8 @@ aws.rds { dbClusters() []aws.rds.dbcluster // List of RDS database clusters clusters() []aws.rds.dbcluster + // List of pending maintenance actions for the database instance + pendingMaintenanceActions() []aws.rds.pendingMaintenanceAction } // Amazon RDS Backup Setting @@ -2230,6 +2232,26 @@ private aws.rds.dbinstance @defaults("id region engine engineVersion") { activityStreamMode string // Status of the database activity stream activityStreamStatus string + // List of pending maintenance actions for the database instance + pendingMaintenanceActions() []aws.rds.pendingMaintenanceAction +} + +// Amazon RDS pending maintenance action +private aws.rds.pendingMaintenanceAction { + // ARN for resource + resourceArn string + // Action to take + action string + // Description of the action + description string + // Auto applied after date + autoAppliedAfterDate time + // Current apply date + currentApplyDate time + // Forced apply date + forcedApplyDate time + // Opt-in status + optInStatus string } // Amazon ElastiCache diff --git a/providers/aws/resources/aws.lr.go b/providers/aws/resources/aws.lr.go index 1d38c1849a..7d7c895b59 100644 --- a/providers/aws/resources/aws.lr.go +++ b/providers/aws/resources/aws.lr.go @@ -530,6 +530,10 @@ func init() { Init: initAwsRdsDbinstance, Create: createAwsRdsDbinstance, }, + "aws.rds.pendingMaintenanceAction": { + // to override args, implement: initAwsRdsPendingMaintenanceAction(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) + Create: createAwsRdsPendingMaintenanceAction, + }, "aws.elasticache": { // to override args, implement: initAwsElasticache(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) Create: createAwsElasticache, @@ -3062,6 +3066,9 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "aws.rds.clusters": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlAwsRds).GetClusters()).ToDataRes(types.Array(types.Resource("aws.rds.dbcluster"))) }, + "aws.rds.pendingMaintenanceActions": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsRds).GetPendingMaintenanceActions()).ToDataRes(types.Array(types.Resource("aws.rds.pendingMaintenanceAction"))) + }, "aws.rds.backupsetting.target": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlAwsRdsBackupsetting).GetTarget()).ToDataRes(types.String) }, @@ -3350,6 +3357,30 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "aws.rds.dbinstance.activityStreamStatus": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlAwsRdsDbinstance).GetActivityStreamStatus()).ToDataRes(types.String) }, + "aws.rds.dbinstance.pendingMaintenanceActions": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsRdsDbinstance).GetPendingMaintenanceActions()).ToDataRes(types.Array(types.Resource("aws.rds.pendingMaintenanceAction"))) + }, + "aws.rds.pendingMaintenanceAction.resourceArn": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsRdsPendingMaintenanceAction).GetResourceArn()).ToDataRes(types.String) + }, + "aws.rds.pendingMaintenanceAction.action": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsRdsPendingMaintenanceAction).GetAction()).ToDataRes(types.String) + }, + "aws.rds.pendingMaintenanceAction.description": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsRdsPendingMaintenanceAction).GetDescription()).ToDataRes(types.String) + }, + "aws.rds.pendingMaintenanceAction.autoAppliedAfterDate": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsRdsPendingMaintenanceAction).GetAutoAppliedAfterDate()).ToDataRes(types.Time) + }, + "aws.rds.pendingMaintenanceAction.currentApplyDate": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsRdsPendingMaintenanceAction).GetCurrentApplyDate()).ToDataRes(types.Time) + }, + "aws.rds.pendingMaintenanceAction.forcedApplyDate": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsRdsPendingMaintenanceAction).GetForcedApplyDate()).ToDataRes(types.Time) + }, + "aws.rds.pendingMaintenanceAction.optInStatus": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsRdsPendingMaintenanceAction).GetOptInStatus()).ToDataRes(types.String) + }, "aws.elasticache.clusters": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlAwsElasticache).GetClusters()).ToDataRes(types.Array(types.Dict)) }, @@ -8099,6 +8130,10 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlAwsRds).Clusters, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) return }, + "aws.rds.pendingMaintenanceActions": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsRds).PendingMaintenanceActions, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, "aws.rds.backupsetting.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { r.(*mqlAwsRdsBackupsetting).__id, ok = v.Value.(string) return @@ -8499,6 +8534,42 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlAwsRdsDbinstance).ActivityStreamStatus, ok = plugin.RawToTValue[string](v.Value, v.Error) return }, + "aws.rds.dbinstance.pendingMaintenanceActions": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsRdsDbinstance).PendingMaintenanceActions, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "aws.rds.pendingMaintenanceAction.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsRdsPendingMaintenanceAction).__id, ok = v.Value.(string) + return + }, + "aws.rds.pendingMaintenanceAction.resourceArn": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsRdsPendingMaintenanceAction).ResourceArn, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "aws.rds.pendingMaintenanceAction.action": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsRdsPendingMaintenanceAction).Action, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "aws.rds.pendingMaintenanceAction.description": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsRdsPendingMaintenanceAction).Description, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "aws.rds.pendingMaintenanceAction.autoAppliedAfterDate": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsRdsPendingMaintenanceAction).AutoAppliedAfterDate, ok = plugin.RawToTValue[*time.Time](v.Value, v.Error) + return + }, + "aws.rds.pendingMaintenanceAction.currentApplyDate": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsRdsPendingMaintenanceAction).CurrentApplyDate, ok = plugin.RawToTValue[*time.Time](v.Value, v.Error) + return + }, + "aws.rds.pendingMaintenanceAction.forcedApplyDate": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsRdsPendingMaintenanceAction).ForcedApplyDate, ok = plugin.RawToTValue[*time.Time](v.Value, v.Error) + return + }, + "aws.rds.pendingMaintenanceAction.optInStatus": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsRdsPendingMaintenanceAction).OptInStatus, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, "aws.elasticache.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { r.(*mqlAwsElasticache).__id, ok = v.Value.(string) return @@ -20851,6 +20922,7 @@ type mqlAwsRds struct { Instances plugin.TValue[[]interface{}] DbClusters plugin.TValue[[]interface{}] Clusters plugin.TValue[[]interface{}] + PendingMaintenanceActions plugin.TValue[[]interface{}] } // createAwsRds creates a new instance of this resource @@ -20954,6 +21026,22 @@ func (c *mqlAwsRds) GetClusters() *plugin.TValue[[]interface{}] { }) } +func (c *mqlAwsRds) GetPendingMaintenanceActions() *plugin.TValue[[]interface{}] { + return plugin.GetOrCompute[[]interface{}](&c.PendingMaintenanceActions, func() ([]interface{}, error) { + if c.MqlRuntime.HasRecording { + d, err := c.MqlRuntime.FieldResourceFromRecording("aws.rds", c.__id, "pendingMaintenanceActions") + if err != nil { + return nil, err + } + if d != nil { + return d.Value.([]interface{}), nil + } + } + + return c.pendingMaintenanceActions() + }) +} + // mqlAwsRdsBackupsetting for the aws.rds.backupsetting resource type mqlAwsRdsBackupsetting struct { MqlRuntime *plugin.Runtime @@ -21457,6 +21545,7 @@ type mqlAwsRdsDbinstance struct { CustomIamInstanceProfile plugin.TValue[string] ActivityStreamMode plugin.TValue[string] ActivityStreamStatus plugin.TValue[string] + PendingMaintenanceActions plugin.TValue[[]interface{}] } // createAwsRdsDbinstance creates a new instance of this resource @@ -21684,6 +21773,96 @@ func (c *mqlAwsRdsDbinstance) GetActivityStreamStatus() *plugin.TValue[string] { return &c.ActivityStreamStatus } +func (c *mqlAwsRdsDbinstance) GetPendingMaintenanceActions() *plugin.TValue[[]interface{}] { + return plugin.GetOrCompute[[]interface{}](&c.PendingMaintenanceActions, func() ([]interface{}, error) { + if c.MqlRuntime.HasRecording { + d, err := c.MqlRuntime.FieldResourceFromRecording("aws.rds.dbinstance", c.__id, "pendingMaintenanceActions") + if err != nil { + return nil, err + } + if d != nil { + return d.Value.([]interface{}), nil + } + } + + return c.pendingMaintenanceActions() + }) +} + +// mqlAwsRdsPendingMaintenanceAction for the aws.rds.pendingMaintenanceAction resource +type mqlAwsRdsPendingMaintenanceAction struct { + MqlRuntime *plugin.Runtime + __id string + // optional: if you define mqlAwsRdsPendingMaintenanceActionInternal it will be used here + ResourceArn plugin.TValue[string] + Action plugin.TValue[string] + Description plugin.TValue[string] + AutoAppliedAfterDate plugin.TValue[*time.Time] + CurrentApplyDate plugin.TValue[*time.Time] + ForcedApplyDate plugin.TValue[*time.Time] + OptInStatus plugin.TValue[string] +} + +// createAwsRdsPendingMaintenanceAction creates a new instance of this resource +func createAwsRdsPendingMaintenanceAction(runtime *plugin.Runtime, args map[string]*llx.RawData) (plugin.Resource, error) { + res := &mqlAwsRdsPendingMaintenanceAction{ + MqlRuntime: runtime, + } + + err := SetAllData(res, args) + if err != nil { + return res, err + } + + // to override __id implement: id() (string, error) + + if runtime.HasRecording { + args, err = runtime.ResourceFromRecording("aws.rds.pendingMaintenanceAction", res.__id) + if err != nil || args == nil { + return res, err + } + return res, SetAllData(res, args) + } + + return res, nil +} + +func (c *mqlAwsRdsPendingMaintenanceAction) MqlName() string { + return "aws.rds.pendingMaintenanceAction" +} + +func (c *mqlAwsRdsPendingMaintenanceAction) MqlID() string { + return c.__id +} + +func (c *mqlAwsRdsPendingMaintenanceAction) GetResourceArn() *plugin.TValue[string] { + return &c.ResourceArn +} + +func (c *mqlAwsRdsPendingMaintenanceAction) GetAction() *plugin.TValue[string] { + return &c.Action +} + +func (c *mqlAwsRdsPendingMaintenanceAction) GetDescription() *plugin.TValue[string] { + return &c.Description +} + +func (c *mqlAwsRdsPendingMaintenanceAction) GetAutoAppliedAfterDate() *plugin.TValue[*time.Time] { + return &c.AutoAppliedAfterDate +} + +func (c *mqlAwsRdsPendingMaintenanceAction) GetCurrentApplyDate() *plugin.TValue[*time.Time] { + return &c.CurrentApplyDate +} + +func (c *mqlAwsRdsPendingMaintenanceAction) GetForcedApplyDate() *plugin.TValue[*time.Time] { + return &c.ForcedApplyDate +} + +func (c *mqlAwsRdsPendingMaintenanceAction) GetOptInStatus() *plugin.TValue[string] { + return &c.OptInStatus +} + // mqlAwsElasticache for the aws.elasticache resource type mqlAwsElasticache struct { MqlRuntime *plugin.Runtime diff --git a/providers/aws/resources/aws.lr.manifest.yaml b/providers/aws/resources/aws.lr.manifest.yaml index 1976ff848f..d1787e9ecd 100755 --- a/providers/aws/resources/aws.lr.manifest.yaml +++ b/providers/aws/resources/aws.lr.manifest.yaml @@ -2264,6 +2264,8 @@ resources: dbInstances: {} instances: min_mondoo_version: 9.0.0 + pendingMaintenanceActions: + min_mondoo_version: 9.0.0 min_mondoo_version: 5.15.0 platform: name: @@ -2418,6 +2420,8 @@ resources: min_mondoo_version: 9.0.0 multiAZ: {} name: {} + pendingMaintenanceActions: + min_mondoo_version: 9.0.0 port: min_mondoo_version: 9.0.0 publiclyAccessible: {} @@ -2442,6 +2446,20 @@ resources: platform: name: - aws + aws.rds.pendingMaintenanceAction: + fields: + action: {} + autoAppliedAfterDate: {} + currentApplyDate: {} + description: {} + forcedApplyDate: {} + optInStatus: {} + resourceArn: {} + is_private: true + min_mondoo_version: 9.0.0 + platform: + name: + - aws aws.rds.snapshot: docs: desc: | diff --git a/providers/aws/resources/aws_rds.go b/providers/aws/resources/aws_rds.go index 1fc43eb624..300596fff9 100644 --- a/providers/aws/resources/aws_rds.go +++ b/providers/aws/resources/aws_rds.go @@ -159,6 +159,73 @@ func (a *mqlAwsRds) getDbInstances(conn *connection.AwsConnection) []*jobpool.Jo return tasks } +// pendingMaintenanceActions returns all pending maintaince actions for all RDS instances +func (a *mqlAwsRds) pendingMaintenanceActions() ([]interface{}, error) { + conn := a.MqlRuntime.Connection.(*connection.AwsConnection) + res := []interface{}{} + poolOfJobs := jobpool.CreatePool(a.getPpendingMaintenanceActions(conn), 5) + poolOfJobs.Run() + + // check for errors + if poolOfJobs.HasErrors() { + return nil, poolOfJobs.GetErrors() + } + // get all the results + for i := range poolOfJobs.Jobs { + res = append(res, poolOfJobs.Jobs[i].Result.([]interface{})...) + } + + return res, nil +} + +func (a *mqlAwsRds) getPpendingMaintenanceActions(conn *connection.AwsConnection) []*jobpool.Job { + tasks := make([]*jobpool.Job, 0) + regions, err := conn.Regions() + if err != nil { + return []*jobpool.Job{{Err: err}} + } + + for _, region := range regions { + regionVal := region + f := func() (jobpool.JobResult, error) { + log.Debug().Msgf("rds>getDbInstances>calling aws with region %s", regionVal) + + res := []interface{}{} + svc := conn.Rds(regionVal) + ctx := context.Background() + + var marker *string + for { + pendingMaintainanceList, err := svc.DescribePendingMaintenanceActions(ctx, &rds.DescribePendingMaintenanceActionsInput{ + Marker: marker, + }) + if err != nil { + return nil, err + } + for _, resp := range pendingMaintainanceList.PendingMaintenanceActions { + if resp.ResourceIdentifier == nil { + continue + } + for _, action := range resp.PendingMaintenanceActionDetails { + resourceArn := *resp.ResourceIdentifier + mqlDbSnapshot, err := newMqlAwsPendingMaintainceAction(a.MqlRuntime, region, resourceArn, action) + if err != nil { + return nil, err + } + res = append(res, mqlDbSnapshot) + } + } + if pendingMaintainanceList.Marker == nil { + break + } + marker = pendingMaintainanceList.Marker + } + return jobpool.JobResult(res), nil + } + tasks = append(tasks, jobpool.NewJob(f)) + } + return tasks +} func (a *mqlAwsRdsDbinstance) id() (string, error) { return a.Arn.Data, nil @@ -255,6 +322,70 @@ func (a *mqlAwsRdsDbinstance) snapshots() ([]interface{}, error) { return res, nil } +// pendingMaintenanceActions returns all pending maintenance actions for the RDS instance +func (a *mqlAwsRdsDbinstance) pendingMaintenanceActions() ([]interface{}, error) { + instanceArn := a.Arn.Data + region := a.Region.Data + conn := a.MqlRuntime.Connection.(*connection.AwsConnection) + + svc := conn.Rds(region) + ctx := context.Background() + res := []interface{}{} + + var marker *string + for { + pendingMaintainanceList, err := svc.DescribePendingMaintenanceActions(ctx, &rds.DescribePendingMaintenanceActionsInput{ + ResourceIdentifier: &instanceArn, + Marker: marker, + }) + if err != nil { + return nil, err + } + for _, resp := range pendingMaintainanceList.PendingMaintenanceActions { + if resp.ResourceIdentifier == nil { + continue + } + for _, action := range resp.PendingMaintenanceActionDetails { + resourceArn := *resp.ResourceIdentifier + mqlDbSnapshot, err := newMqlAwsPendingMaintainceAction(a.MqlRuntime, region, resourceArn, action) + if err != nil { + return nil, err + } + res = append(res, mqlDbSnapshot) + } + } + if pendingMaintainanceList.Marker == nil { + break + } + marker = pendingMaintainanceList.Marker + } + return res, nil +} + +// newMqlAwsPendingMaintainceaction creates a new mqlAwsRdsPendingMaintenanceActions from a rdstypes.PendingMaintenanceAction +func newMqlAwsPendingMaintainceAction(runtime *plugin.Runtime, region string, resourceArn string, maintenanceAction rdstypes.PendingMaintenanceAction) (*mqlAwsRdsPendingMaintenanceAction, error) { + action := "" + if maintenanceAction.Action != nil { + action = *maintenanceAction.Action + } + + res, err := CreateResource(runtime, "aws.rds.pendingMaintenanceAction", + map[string]*llx.RawData{ + "__id": llx.StringData(fmt.Sprintf("%s/pendingMaintainance/%s", resourceArn, action)), + "resourceArn": llx.StringData(resourceArn), + "action": llx.StringDataPtr(maintenanceAction.Action), + "description": llx.StringDataPtr(maintenanceAction.Description), + "autoAppliedAfterDate": llx.TimeDataPtr(maintenanceAction.AutoAppliedAfterDate), + "currentApplyDate": llx.TimeDataPtr(maintenanceAction.CurrentApplyDate), + "forcedApplyDate": llx.TimeDataPtr(maintenanceAction.ForcedApplyDate), + "optInStatus": llx.StringDataPtr(maintenanceAction.OptInStatus), + }) + if err != nil { + return nil, err + } + return res.(*mqlAwsRdsPendingMaintenanceAction), nil +} + func rdsTagsToMap(tags []rdstypes.Tag) map[string]interface{} { tagsMap := make(map[string]interface{})