diff --git a/client/mocks/mock_lightsail.go b/client/mocks/mock_lightsail.go index 5534681ff..32d3fc5dc 100644 --- a/client/mocks/mock_lightsail.go +++ b/client/mocks/mock_lightsail.go @@ -95,6 +95,46 @@ func (mr *MockLightsailClientMockRecorder) GetBuckets(arg0, arg1 interface{}, ar return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBuckets", reflect.TypeOf((*MockLightsailClient)(nil).GetBuckets), varargs...) } +// GetDiskSnapshots mocks base method. +func (m *MockLightsailClient) GetDiskSnapshots(arg0 context.Context, arg1 *lightsail.GetDiskSnapshotsInput, arg2 ...func(*lightsail.Options)) (*lightsail.GetDiskSnapshotsOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetDiskSnapshots", varargs...) + ret0, _ := ret[0].(*lightsail.GetDiskSnapshotsOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDiskSnapshots indicates an expected call of GetDiskSnapshots. +func (mr *MockLightsailClientMockRecorder) GetDiskSnapshots(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, "GetDiskSnapshots", reflect.TypeOf((*MockLightsailClient)(nil).GetDiskSnapshots), varargs...) +} + +// GetDisks mocks base method. +func (m *MockLightsailClient) GetDisks(arg0 context.Context, arg1 *lightsail.GetDisksInput, arg2 ...func(*lightsail.Options)) (*lightsail.GetDisksOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetDisks", varargs...) + ret0, _ := ret[0].(*lightsail.GetDisksOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDisks indicates an expected call of GetDisks. +func (mr *MockLightsailClientMockRecorder) GetDisks(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, "GetDisks", reflect.TypeOf((*MockLightsailClient)(nil).GetDisks), varargs...) +} + // GetInstances mocks base method. func (m *MockLightsailClient) GetInstances(arg0 context.Context, arg1 *lightsail.GetInstancesInput, arg2 ...func(*lightsail.Options)) (*lightsail.GetInstancesOutput, error) { m.ctrl.T.Helper() diff --git a/client/services.go b/client/services.go index 80481b3b0..d3b5afee3 100644 --- a/client/services.go +++ b/client/services.go @@ -375,6 +375,8 @@ type LightsailClient interface { GetInstances(ctx context.Context, params *lightsail.GetInstancesInput, optFns ...func(*lightsail.Options)) (*lightsail.GetInstancesOutput, error) GetBuckets(ctx context.Context, params *lightsail.GetBucketsInput, optFns ...func(*lightsail.Options)) (*lightsail.GetBucketsOutput, error) GetBucketAccessKeys(ctx context.Context, params *lightsail.GetBucketAccessKeysInput, optFns ...func(*lightsail.Options)) (*lightsail.GetBucketAccessKeysOutput, error) + GetDisks(ctx context.Context, params *lightsail.GetDisksInput, optFns ...func(*lightsail.Options)) (*lightsail.GetDisksOutput, error) + GetDiskSnapshots(ctx context.Context, params *lightsail.GetDiskSnapshotsInput, optFns ...func(*lightsail.Options)) (*lightsail.GetDiskSnapshotsOutput, error) GetAlarms(ctx context.Context, params *lightsail.GetAlarmsInput, optFns ...func(*lightsail.Options)) (*lightsail.GetAlarmsOutput, error) } diff --git a/docs/tables/aws_lightsail_disk_add_ons.md b/docs/tables/aws_lightsail_disk_add_ons.md new file mode 100644 index 000000000..3bc590c75 --- /dev/null +++ b/docs/tables/aws_lightsail_disk_add_ons.md @@ -0,0 +1,11 @@ + +# Table: aws_lightsail_disk_add_ons +Describes an add-on that is enabled for an Amazon Lightsail resource +## Columns +| Name | Type | Description | +| ------------- | ------------- | ----- | +|disk_cq_id|uuid|Unique CloudQuery ID of aws_lightsail_disks table (FK)| +|name|text|The name of the add-on| +|next_snapshot_time_of_day|text|The next daily time an automatic snapshot will be created| +|snapshot_time_of_day|text|The daily time when an automatic snapshot is created| +|status|text|The status of the add-on| diff --git a/docs/tables/aws_lightsail_disk_snapshot.md b/docs/tables/aws_lightsail_disk_snapshot.md new file mode 100644 index 000000000..6988480b0 --- /dev/null +++ b/docs/tables/aws_lightsail_disk_snapshot.md @@ -0,0 +1,23 @@ + +# Table: aws_lightsail_disk_snapshot +Describes a block storage disk snapshot +## Columns +| Name | Type | Description | +| ------------- | ------------- | ----- | +|disk_cq_id|uuid|Unique CloudQuery ID of aws_lightsail_disks table (FK)| +|arn|text|The Amazon Resource Name (ARN) of the disk snapshot| +|created_at|timestamp without time zone|The date when the disk snapshot was created| +|from_disk_arn|text|The Amazon Resource Name (ARN) of the source disk from which the disk snapshot was created| +|from_disk_name|text|The unique name of the source disk from which the disk snapshot was created| +|from_instance_arn|text|The Amazon Resource Name (ARN) of the source instance from which the disk (system volume) snapshot was created| +|from_instance_name|text|The unique name of the source instance from which the disk (system volume) snapshot was created| +|is_from_auto_snapshot|boolean|A Boolean value indicating whether the snapshot was created from an automatic snapshot| +|location_availability_zone|text|The Availability Zone| +|location_region_name|text|The AWS Region name| +|name|text|The name of the disk snapshot (eg, my-disk-snapshot)| +|progress|text|The progress of the snapshot| +|resource_type|text|The Lightsail resource type (eg, DiskSnapshot)| +|size_in_gb|integer|The size of the disk in GB| +|state|text|The status of the disk snapshot operation| +|support_code|text|The support code| +|tags|jsonb|The tag keys and optional values for the resource| diff --git a/docs/tables/aws_lightsail_disks.md b/docs/tables/aws_lightsail_disks.md new file mode 100644 index 000000000..f93608d59 --- /dev/null +++ b/docs/tables/aws_lightsail_disks.md @@ -0,0 +1,25 @@ + +# Table: aws_lightsail_disks +Describes a block storage disk +## 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 disk| +|attached_to|text|The resources to which the disk is attached| +|attachment_state|text|(Deprecated) The attachment state of the disk| +|created_at|timestamp without time zone|The date when the disk was created| +|gb_in_use|integer|(Deprecated) The number of GB in use by the disk| +|iops|integer|The input/output operations per second (IOPS) of the disk| +|is_attached|boolean|A Boolean value indicating whether the disk is attached| +|is_system_disk|boolean|A Boolean value indicating whether this disk is a system disk (has an operating system loaded on it)| +|location_availability_zone|text|The Availability Zone| +|location_region_name|text|The AWS Region name| +|name|text|The unique name of the disk| +|path|text|The disk path| +|resource_type|text|The Lightsail resource type (eg, Disk)| +|size_in_gb|integer|The size of the disk in GB| +|state|text|Describes the status of the disk| +|support_code|text|The support code| +|tags|jsonb|The tag keys and optional values for the resource| diff --git a/resources/provider/provider.go b/resources/provider/provider.go index 0a4432bf8..c40dabe60 100644 --- a/resources/provider/provider.go +++ b/resources/provider/provider.go @@ -191,6 +191,7 @@ func Provider() *provider.Provider { "lambda.runtimes": lambda.LambdaRuntimes(), "lightsail.alarms": lightsail.Alarms(), "lightsail.buckets": lightsail.Buckets(), + "lightsail.disks": lightsail.Disks(), "lightsail.instances": lightsail.Instances(), "mq.brokers": mq.Brokers(), "organizations.accounts": organizations.Accounts(), diff --git a/resources/services/lightsail/disks.go b/resources/services/lightsail/disks.go new file mode 100644 index 000000000..6496ca8f7 --- /dev/null +++ b/resources/services/lightsail/disks.go @@ -0,0 +1,321 @@ +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 disks --config gen.hcl --output . +func Disks() *schema.Table { + return &schema.Table{ + Name: "aws_lightsail_disks", + Description: "Describes a block storage disk", + Resolver: fetchLightsailDisks, + Multiplex: client.ServiceAccountRegionMultiplexer("lightsail"), + IgnoreError: client.IgnoreAccessDeniedServiceDisabled, + DeleteFilter: client.DeleteAccountRegionFilter, + Options: schema.TableCreationOptions{PrimaryKeys: []string{"arn"}}, + 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 disk", + Type: schema.TypeString, + }, + { + Name: "attached_to", + Description: "The resources to which the disk is attached", + Type: schema.TypeString, + }, + { + Name: "attachment_state", + Description: "(Deprecated) The attachment state of the disk", + Type: schema.TypeString, + }, + { + Name: "created_at", + Description: "The date when the disk was created", + Type: schema.TypeTimestamp, + }, + { + Name: "gb_in_use", + Description: "(Deprecated) The number of GB in use by the disk", + Type: schema.TypeInt, + IgnoreInTests: true, + }, + { + Name: "iops", + Description: "The input/output operations per second (IOPS) of the disk", + Type: schema.TypeInt, + }, + { + Name: "is_attached", + Description: "A Boolean value indicating whether the disk is attached", + Type: schema.TypeBool, + }, + { + Name: "is_system_disk", + Description: "A Boolean value indicating whether this disk is a system disk (has an operating system loaded on it)", + Type: schema.TypeBool, + }, + { + Name: "location_availability_zone", + Description: "The Availability Zone", + Type: schema.TypeString, + Resolver: schema.PathResolver("Location.AvailabilityZone"), + }, + { + Name: "location_region_name", + Description: "The AWS Region name", + Type: schema.TypeString, + Resolver: schema.PathResolver("Location.RegionName"), + }, + { + Name: "name", + Description: "The unique name of the disk", + Type: schema.TypeString, + }, + { + Name: "path", + Description: "The disk path", + Type: schema.TypeString, + }, + { + Name: "resource_type", + Description: "The Lightsail resource type (eg, Disk)", + Type: schema.TypeString, + }, + { + Name: "size_in_gb", + Description: "The size of the disk in GB", + Type: schema.TypeInt, + }, + { + Name: "state", + Description: "Describes the status of the disk", + Type: schema.TypeString, + }, + { + Name: "support_code", + Description: "The support code", + Type: schema.TypeString, + }, + { + Name: "tags", + Description: "The tag keys and optional values for the resource", + Type: schema.TypeJSON, + Resolver: resolveDisksTags, + }, + }, + Relations: []*schema.Table{ + { + Name: "aws_lightsail_disk_add_ons", + Description: "Describes an add-on that is enabled for an Amazon Lightsail resource", + Resolver: fetchLightsailDiskAddOns, + IgnoreInTests: true, + Columns: []schema.Column{ + { + Name: "disk_cq_id", + Description: "Unique CloudQuery ID of aws_lightsail_disks table (FK)", + Type: schema.TypeUUID, + Resolver: schema.ParentIdResolver, + }, + { + Name: "name", + Description: "The name of the add-on", + Type: schema.TypeString, + }, + { + Name: "next_snapshot_time_of_day", + Description: "The next daily time an automatic snapshot will be created", + Type: schema.TypeString, + }, + { + Name: "snapshot_time_of_day", + Description: "The daily time when an automatic snapshot is created", + Type: schema.TypeString, + }, + { + Name: "status", + Description: "The status of the add-on", + Type: schema.TypeString, + }, + }, + }, + { + Name: "aws_lightsail_disk_snapshot", + Description: "Describes a block storage disk snapshot", + Resolver: fetchLightsailDiskSnapshots, + IgnoreInTests: true, + Columns: []schema.Column{ + { + Name: "disk_cq_id", + Description: "Unique CloudQuery ID of aws_lightsail_disks table (FK)", + Type: schema.TypeUUID, + Resolver: schema.ParentIdResolver, + }, + { + Name: "arn", + Description: "The Amazon Resource Name (ARN) of the disk snapshot", + Type: schema.TypeString, + }, + { + Name: "created_at", + Description: "The date when the disk snapshot was created", + Type: schema.TypeTimestamp, + }, + { + Name: "from_disk_arn", + Description: "The Amazon Resource Name (ARN) of the source disk from which the disk snapshot was created", + Type: schema.TypeString, + }, + { + Name: "from_disk_name", + Description: "The unique name of the source disk from which the disk snapshot was created", + Type: schema.TypeString, + }, + { + Name: "from_instance_arn", + Description: "The Amazon Resource Name (ARN) of the source instance from which the disk (system volume) snapshot was created", + Type: schema.TypeString, + }, + { + Name: "from_instance_name", + Description: "The unique name of the source instance from which the disk (system volume) snapshot was created", + Type: schema.TypeString, + }, + { + Name: "is_from_auto_snapshot", + Description: "A Boolean value indicating whether the snapshot was created from an automatic snapshot", + Type: schema.TypeBool, + }, + { + Name: "location_availability_zone", + Description: "The Availability Zone", + Type: schema.TypeString, + Resolver: schema.PathResolver("Location.AvailabilityZone"), + }, + { + Name: "location_region_name", + Description: "The AWS Region name", + Type: schema.TypeString, + Resolver: schema.PathResolver("Location.RegionName"), + }, + { + Name: "name", + Description: "The name of the disk snapshot (eg, my-disk-snapshot)", + Type: schema.TypeString, + }, + { + Name: "progress", + Description: "The progress of the snapshot", + Type: schema.TypeString, + }, + { + Name: "resource_type", + Description: "The Lightsail resource type (eg, DiskSnapshot)", + Type: schema.TypeString, + }, + { + Name: "size_in_gb", + Description: "The size of the disk in GB", + Type: schema.TypeInt, + }, + { + Name: "state", + Description: "The status of the disk snapshot operation", + Type: schema.TypeString, + }, + { + Name: "support_code", + Description: "The support code", + Type: schema.TypeString, + }, + { + Name: "tags", + Description: "The tag keys and optional values for the resource", + Type: schema.TypeJSON, + Resolver: resolveDiskSnapshotsTags, + }, + }, + }, + }, + } +} + +// ==================================================================================================================== +// Table Resolver Functions +// ==================================================================================================================== + +func fetchLightsailDisks(ctx context.Context, meta schema.ClientMeta, parent *schema.Resource, res chan<- interface{}) error { + var input lightsail.GetDisksInput + c := meta.(*client.Client) + svc := c.Services().Lightsail + for { + response, err := svc.GetDisks(ctx, &input, func(options *lightsail.Options) { + options.Region = c.Region + }) + if err != nil { + return diag.WrapError(err) + } + res <- response.Disks + if aws.ToString(response.NextPageToken) == "" { + break + } + input.PageToken = response.NextPageToken + } + return nil +} +func resolveDisksTags(ctx context.Context, meta schema.ClientMeta, resource *schema.Resource, c schema.Column) error { + r := resource.Item.(types.Disk) + tags := make(map[string]string) + client.TagsIntoMap(r.Tags, tags) + return diag.WrapError(resource.Set(c.Name, tags)) +} +func fetchLightsailDiskAddOns(ctx context.Context, meta schema.ClientMeta, parent *schema.Resource, res chan<- interface{}) error { + r := parent.Item.(types.Disk) + res <- r.AddOns + return nil +} +func fetchLightsailDiskSnapshots(ctx context.Context, meta schema.ClientMeta, parent *schema.Resource, res chan<- interface{}) error { + var input lightsail.GetDiskSnapshotsInput + c := meta.(*client.Client) + svc := c.Services().Lightsail + for { + response, err := svc.GetDiskSnapshots(ctx, &input, func(options *lightsail.Options) { + options.Region = c.Region + }) + if err != nil { + return diag.WrapError(err) + } + res <- response.DiskSnapshots + if aws.ToString(response.NextPageToken) == "" { + break + } + input.PageToken = response.NextPageToken + } + return nil +} +func resolveDiskSnapshotsTags(ctx context.Context, meta schema.ClientMeta, resource *schema.Resource, c schema.Column) error { + r := resource.Item.(types.DiskSnapshot) + tags := make(map[string]string) + client.TagsIntoMap(r.Tags, tags) + return diag.WrapError(resource.Set(c.Name, tags)) +} diff --git a/resources/services/lightsail/disks_mock_test.go b/resources/services/lightsail/disks_mock_test.go new file mode 100644 index 000000000..4d0c78e5b --- /dev/null +++ b/resources/services/lightsail/disks_mock_test.go @@ -0,0 +1,49 @@ +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 buildDisks(t *testing.T, ctrl *gomock.Controller) client.Services { + mock := mocks.NewMockLightsailClient(ctrl) + + var disks lightsail.GetDisksOutput + if err := faker.FakeData(&disks); err != nil { + t.Fatal(err) + } + disks.NextPageToken = nil + mock.EXPECT().GetDisks( + gomock.Any(), + &lightsail.GetDisksInput{}, + gomock.Any(), + ).Return( + &disks, + nil, + ) + + var diskSnapshots lightsail.GetDiskSnapshotsOutput + if err := faker.FakeData(&diskSnapshots); err != nil { + t.Fatal(err) + } + diskSnapshots.NextPageToken = nil + mock.EXPECT().GetDiskSnapshots( + gomock.Any(), + &lightsail.GetDiskSnapshotsInput{}, + gomock.Any(), + ).Return( + &diskSnapshots, + nil, + ) + + return client.Services{Lightsail: mock} +} + +func TestLightsailDisks(t *testing.T) { + client.AwsMockTestHelper(t, Disks(), buildDisks, client.TestOptions{}) +} diff --git a/resources/services/lightsail/gen.hcl b/resources/services/lightsail/gen.hcl index 22a6d2de7..0e3114298 100644 --- a/resources/services/lightsail/gen.hcl +++ b/resources/services/lightsail/gen.hcl @@ -120,6 +120,55 @@ resource "aws" "lightsail" "buckets" { } +resource "aws" "lightsail" "disks" { + path = "github.com/aws/aws-sdk-go-v2/service/lightsail/types.Disk" + 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 + } + + user_relation "aws" "lightsail" "disk_snapshot" { + path = "github.com/aws/aws-sdk-go-v2/service/lightsail/types.DiskSnapshot" + + column "tags" { + type = "json" + generate_resolver = true + } + } +} + + resource "aws" "lightsail" "alarms" { path = "github.com/aws/aws-sdk-go-v2/service/lightsail/types.Alarm" ignoreError "IgnoreAccessDenied" {