From 6749225829e3262d83e9ba44d15a0f055dc0f8e2 Mon Sep 17 00:00:00 2001 From: Andrii Romanenko Date: Fri, 22 Jul 2022 11:12:21 +0100 Subject: [PATCH] feat: Added lightsail database snapshots (#1263) * feat: Added lightsail database snapshots * generate mock --- client/mocks/mock_lightsail.go | 20 +++ client/services.go | 1 + .../aws_lightsail_database_snapshots.md | 23 +++ resources/provider/provider.go | 1 + .../services/lightsail/database_snapshots.go | 147 ++++++++++++++++++ .../lightsail/database_snapshots_mock_test.go | 32 ++++ resources/services/lightsail/gen.hcl | 47 ++++++ 7 files changed, 271 insertions(+) create mode 100644 docs/tables/aws_lightsail_database_snapshots.md create mode 100644 resources/services/lightsail/database_snapshots.go create mode 100644 resources/services/lightsail/database_snapshots_mock_test.go diff --git a/client/mocks/mock_lightsail.go b/client/mocks/mock_lightsail.go index 082e466c4..647106f62 100644 --- a/client/mocks/mock_lightsail.go +++ b/client/mocks/mock_lightsail.go @@ -175,6 +175,26 @@ func (mr *MockLightsailClientMockRecorder) GetInstances(arg0, arg1 interface{}, return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInstances", reflect.TypeOf((*MockLightsailClient)(nil).GetInstances), varargs...) } +// GetRelationalDatabaseSnapshots mocks base method. +func (m *MockLightsailClient) GetRelationalDatabaseSnapshots(arg0 context.Context, arg1 *lightsail.GetRelationalDatabaseSnapshotsInput, arg2 ...func(*lightsail.Options)) (*lightsail.GetRelationalDatabaseSnapshotsOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetRelationalDatabaseSnapshots", varargs...) + ret0, _ := ret[0].(*lightsail.GetRelationalDatabaseSnapshotsOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetRelationalDatabaseSnapshots indicates an expected call of GetRelationalDatabaseSnapshots. +func (mr *MockLightsailClientMockRecorder) GetRelationalDatabaseSnapshots(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRelationalDatabaseSnapshots", reflect.TypeOf((*MockLightsailClient)(nil).GetRelationalDatabaseSnapshots), varargs...) +} + // GetStaticIps mocks base method. func (m *MockLightsailClient) GetStaticIps(arg0 context.Context, arg1 *lightsail.GetStaticIpsInput, arg2 ...func(*lightsail.Options)) (*lightsail.GetStaticIpsOutput, error) { m.ctrl.T.Helper() diff --git a/client/services.go b/client/services.go index e433de8c3..ff4f658f3 100644 --- a/client/services.go +++ b/client/services.go @@ -380,6 +380,7 @@ type LightsailClient interface { GetAlarms(ctx context.Context, params *lightsail.GetAlarmsInput, optFns ...func(*lightsail.Options)) (*lightsail.GetAlarmsOutput, error) GetCertificates(ctx context.Context, params *lightsail.GetCertificatesInput, optFns ...func(*lightsail.Options)) (*lightsail.GetCertificatesOutput, error) GetStaticIps(ctx context.Context, params *lightsail.GetStaticIpsInput, optFns ...func(*lightsail.Options)) (*lightsail.GetStaticIpsOutput, error) + GetRelationalDatabaseSnapshots(ctx context.Context, params *lightsail.GetRelationalDatabaseSnapshotsInput, optFns ...func(*lightsail.Options)) (*lightsail.GetRelationalDatabaseSnapshotsOutput, error) } //go:generate mockgen -package=mocks -destination=./mocks/mock_mq.go . MQClient diff --git a/docs/tables/aws_lightsail_database_snapshots.md b/docs/tables/aws_lightsail_database_snapshots.md new file mode 100644 index 000000000..03c770c4c --- /dev/null +++ b/docs/tables/aws_lightsail_database_snapshots.md @@ -0,0 +1,23 @@ + +# Table: aws_lightsail_database_snapshots +Describes a database snapshot +## Columns +| Name | Type | Description | +| ------------- | ------------- | ----- | +|account_id|text|The AWS Account ID of the resource.| +|region|text|The AWS Region of the resource.| +|arn|text|The Amazon Resource Name (ARN) of the database snapshot| +|created_at|timestamp without time zone|The timestamp when the database snapshot was created| +|engine|text|The software of the database snapshot (for example, MySQL)| +|engine_version|text|The database engine version for the database snapshot (for example, 5723)| +|from_relational_database_arn|text|The Amazon Resource Name (ARN) of the database from which the database snapshot was created| +|from_relational_database_blueprint_id|text|The blueprint ID of the database from which the database snapshot was created| +|from_relational_database_bundle_id|text|The bundle ID of the database from which the database snapshot was created| +|from_relational_database_name|text|The name of the source database from which the database snapshot was created| +|availability_zone|text|The Availability Zone| +|name|text|The name of the database snapshot| +|resource_type|text|The Lightsail resource type| +|size_in_gb|integer|The size of the disk in GB (for example, 32) for the database snapshot| +|state|text|The state of the database snapshot| +|support_code|text|The support code for the database snapshot| +|tags|jsonb|The tag keys and optional values for the resource| diff --git a/resources/provider/provider.go b/resources/provider/provider.go index c42e855c0..e97ddf7d8 100644 --- a/resources/provider/provider.go +++ b/resources/provider/provider.go @@ -192,6 +192,7 @@ func Provider() *provider.Provider { "lightsail.alarms": lightsail.Alarms(), "lightsail.buckets": lightsail.Buckets(), "lightsail.certificates": lightsail.Certificates(), + "lightsail.database_snapshots": lightsail.DatabaseSnapshots(), "lightsail.disks": lightsail.Disks(), "lightsail.instances": lightsail.Instances(), "lightsail.static_ips": lightsail.StaticIps(), diff --git a/resources/services/lightsail/database_snapshots.go b/resources/services/lightsail/database_snapshots.go new file mode 100644 index 000000000..9e9dc31d0 --- /dev/null +++ b/resources/services/lightsail/database_snapshots.go @@ -0,0 +1,147 @@ +package lightsail + +import ( + "context" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/lightsail" + "github.com/aws/aws-sdk-go-v2/service/lightsail/types" + "github.com/cloudquery/cq-provider-aws/client" + "github.com/cloudquery/cq-provider-sdk/provider/diag" + "github.com/cloudquery/cq-provider-sdk/provider/schema" +) + +//go:generate cq-gen --resource database_snapshots --config gen.hcl --output . +func DatabaseSnapshots() *schema.Table { + return &schema.Table{ + Name: "aws_lightsail_database_snapshots", + Description: "Describes a database snapshot", + Resolver: fetchLightsailDatabaseSnapshots, + Multiplex: client.ServiceAccountRegionMultiplexer("lightsail"), + IgnoreError: client.IgnoreAccessDeniedServiceDisabled, + DeleteFilter: client.DeleteAccountRegionFilter, + Options: schema.TableCreationOptions{PrimaryKeys: []string{"arn"}}, + IgnoreInTests: true, // can't be created using terraform. + Columns: []schema.Column{ + { + Name: "account_id", + Description: "The AWS Account ID of the resource.", + Type: schema.TypeString, + Resolver: client.ResolveAWSAccount, + }, + { + Name: "region", + Description: "The AWS Region of the resource.", + Type: schema.TypeString, + Resolver: client.ResolveAWSRegion, + }, + { + Name: "arn", + Description: "The Amazon Resource Name (ARN) of the database snapshot", + Type: schema.TypeString, + }, + { + Name: "created_at", + Description: "The timestamp when the database snapshot was created", + Type: schema.TypeTimestamp, + }, + { + Name: "engine", + Description: "The software of the database snapshot (for example, MySQL)", + Type: schema.TypeString, + }, + { + Name: "engine_version", + Description: "The database engine version for the database snapshot (for example, 5723)", + Type: schema.TypeString, + }, + { + Name: "from_relational_database_arn", + Description: "The Amazon Resource Name (ARN) of the database from which the database snapshot was created", + Type: schema.TypeString, + }, + { + Name: "from_relational_database_blueprint_id", + Description: "The blueprint ID of the database from which the database snapshot was created", + Type: schema.TypeString, + }, + { + Name: "from_relational_database_bundle_id", + Description: "The bundle ID of the database from which the database snapshot was created", + Type: schema.TypeString, + }, + { + Name: "from_relational_database_name", + Description: "The name of the source database from which the database snapshot was created", + Type: schema.TypeString, + }, + { + Name: "availability_zone", + Description: "The Availability Zone", + Type: schema.TypeString, + Resolver: schema.PathResolver("Location.AvailabilityZone"), + }, + { + Name: "name", + Description: "The name of the database snapshot", + Type: schema.TypeString, + }, + { + Name: "resource_type", + Description: "The Lightsail resource type", + Type: schema.TypeString, + }, + { + Name: "size_in_gb", + Description: "The size of the disk in GB (for example, 32) for the database snapshot", + Type: schema.TypeInt, + }, + { + Name: "state", + Description: "The state of the database snapshot", + Type: schema.TypeString, + }, + { + Name: "support_code", + Description: "The support code for the database snapshot", + Type: schema.TypeString, + }, + { + Name: "tags", + Description: "The tag keys and optional values for the resource", + Type: schema.TypeJSON, + Resolver: resolveDatabaseSnapshotsTags, + }, + }, + } +} + +// ==================================================================================================================== +// Table Resolver Functions +// ==================================================================================================================== + +func fetchLightsailDatabaseSnapshots(ctx context.Context, meta schema.ClientMeta, parent *schema.Resource, res chan<- interface{}) error { + var input lightsail.GetRelationalDatabaseSnapshotsInput + c := meta.(*client.Client) + svc := c.Services().Lightsail + for { + response, err := svc.GetRelationalDatabaseSnapshots(ctx, &input, func(options *lightsail.Options) { + options.Region = c.Region + }) + if err != nil { + return diag.WrapError(err) + } + res <- response.RelationalDatabaseSnapshots + if aws.ToString(response.NextPageToken) == "" { + break + } + input.PageToken = response.NextPageToken + } + return nil +} +func resolveDatabaseSnapshotsTags(ctx context.Context, meta schema.ClientMeta, resource *schema.Resource, c schema.Column) error { + r := resource.Item.(types.RelationalDatabaseSnapshot) + tags := make(map[string]string) + client.TagsIntoMap(r.Tags, tags) + return diag.WrapError(resource.Set(c.Name, tags)) +} diff --git a/resources/services/lightsail/database_snapshots_mock_test.go b/resources/services/lightsail/database_snapshots_mock_test.go new file mode 100644 index 000000000..214a61b85 --- /dev/null +++ b/resources/services/lightsail/database_snapshots_mock_test.go @@ -0,0 +1,32 @@ +package lightsail + +import ( + "testing" + + "github.com/aws/aws-sdk-go-v2/service/lightsail" + "github.com/cloudquery/cq-provider-aws/client" + "github.com/cloudquery/cq-provider-aws/client/mocks" + "github.com/cloudquery/faker/v3" + "github.com/golang/mock/gomock" +) + +func buildDatabaseSnapshotsMock(t *testing.T, ctrl *gomock.Controller) client.Services { + m := mocks.NewMockLightsailClient(ctrl) + + s := lightsail.GetRelationalDatabaseSnapshotsOutput{} + err := faker.FakeData(&s) + if err != nil { + t.Fatal(err) + } + s.NextPageToken = nil + m.EXPECT().GetRelationalDatabaseSnapshots(gomock.Any(), gomock.Any(), gomock.Any()).Return( + &s, nil) + + return client.Services{ + Lightsail: m, + } +} + +func TestDatabaseSnapshots(t *testing.T) { + client.AwsMockTestHelper(t, DatabaseSnapshots(), buildDatabaseSnapshotsMock, client.TestOptions{}) +} diff --git a/resources/services/lightsail/gen.hcl b/resources/services/lightsail/gen.hcl index 71d4edb59..5ed919055 100644 --- a/resources/services/lightsail/gen.hcl +++ b/resources/services/lightsail/gen.hcl @@ -317,3 +317,50 @@ resource "aws" "lightsail" "static_ips" { skip = true } } + + + + +resource "aws" "lightsail" "database_snapshots" { + path = "github.com/aws/aws-sdk-go-v2/service/lightsail/types.RelationalDatabaseSnapshot" + ignoreError "IgnoreAccessDenied" { + path = "github.com/cloudquery/cq-provider-aws/client.IgnoreAccessDeniedServiceDisabled" + } + multiplex "AwsAccountRegion" { + path = "github.com/cloudquery/cq-provider-aws/client.ServiceAccountRegionMultiplexer" + params = ["lightsail"] + } + deleteFilter "AccountRegionFilter" { + path = "github.com/cloudquery/cq-provider-aws/client.DeleteAccountRegionFilter" + } + + options { + primary_keys = [ + "arn" + ] + } + userDefinedColumn "account_id" { + type = "string" + description = "The AWS Account ID of the resource." + resolver "resolveAWSAccount" { + path = "github.com/cloudquery/cq-provider-aws/client.ResolveAWSAccount" + } + } + userDefinedColumn "region" { + type = "string" + description = "The AWS Region of the resource." + resolver "resolveAWSRegion" { + path = "github.com/cloudquery/cq-provider-aws/client.ResolveAWSRegion" + } + } + column "tags" { + type = "json" + generate_resolver = true + } + column "location" { + skip_prefix = true + } + column "region_name" { + skip = true + } +} \ No newline at end of file