diff --git a/resources/iottwinmaker-component-type.go b/resources/iottwinmaker-component-type.go new file mode 100644 index 00000000..c4bba086 --- /dev/null +++ b/resources/iottwinmaker-component-type.go @@ -0,0 +1,145 @@ +package resources + +import ( + "context" + "fmt" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iottwinmaker" + + "github.com/ekristen/libnuke/pkg/registry" + "github.com/ekristen/libnuke/pkg/resource" + "github.com/ekristen/libnuke/pkg/types" + + "github.com/ekristen/aws-nuke/v3/pkg/nuke" +) + +const IoTTwinMakerComponentTypeResource = "IoTTwinMakerComponentType" + +func init() { + registry.Register(®istry.Registration{ + Name: IoTTwinMakerComponentTypeResource, + Scope: nuke.Account, + Lister: &IoTTwinMakerComponentTypeLister{}, + }) +} + +type IoTTwinMakerComponentTypeLister struct{} + +func (l *IoTTwinMakerComponentTypeLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { + opts := o.(*nuke.ListerOpts) + + svc := iottwinmaker.New(opts.Session) + resources := make([]resource.Resource, 0) + + // Require to have workspaces identifiers to query components + workspaceListResponse, err := ListWorkspacesComponentType(svc) + + if err != nil { + return nil, err + } + + for _, workspaceResponse := range workspaceListResponse { + params := &iottwinmaker.ListComponentTypesInput{ + WorkspaceId: workspaceResponse.WorkspaceId, + MaxResults: aws.Int64(25), + } + + for { + resp, err := svc.ListComponentTypes(params) + if err != nil { + return nil, err + } + + for _, item := range resp.ComponentTypeSummaries { + // We must filter out amazon-owned component types when querying tags, + // because their ARN format causes ListTagsForResource to vail with validation error + tags := make(map[string]*string) + if !strings.Contains(*item.Arn, "AmazonOwnedTypesWorkspace") { + tagResp, err := svc.ListTagsForResource( + &iottwinmaker.ListTagsForResourceInput{ + ResourceARN: item.Arn, + }) + if err != nil { + return nil, err + } + tags = tagResp.Tags + } + + resources = append(resources, &IoTTwinMakerComponentType{ + svc: svc, + ID: item.ComponentTypeId, + arn: item.Arn, + tags: tags, + workspaceID: workspaceResponse.WorkspaceId, + }) + } + + if resp.NextToken == nil { + break + } + + params.NextToken = resp.NextToken + } + } + + return resources, nil +} + +// Utility function to list workspaces +func ListWorkspacesComponentType(svc *iottwinmaker.IoTTwinMaker) ([]*iottwinmaker.WorkspaceSummary, error) { + resources := make([]*iottwinmaker.WorkspaceSummary, 0) + params := &iottwinmaker.ListWorkspacesInput{ + MaxResults: aws.Int64(25), + } + for { + resp, err := svc.ListWorkspaces(params) + if err != nil { + return nil, err + } + resources = append(resources, resp.WorkspaceSummaries...) + if resp.NextToken == nil { + break + } + params.NextToken = resp.NextToken + } + return resources, nil +} + +type IoTTwinMakerComponentType struct { + svc *iottwinmaker.IoTTwinMaker + ID *string + workspaceID *string + arn *string + tags map[string]*string +} + +func (f *IoTTwinMakerComponentType) Filter() error { + if strings.Contains(*f.arn, "AmazonOwnedTypesWorkspace") { + return fmt.Errorf("cannot delete pre-defined component type") + } + return nil +} + +func (f *IoTTwinMakerComponentType) Properties() types.Properties { + properties := types.NewProperties() + properties.Set("workspaceID", f.workspaceID) + for k, v := range f.tags { + properties.SetTag(&k, v) + } + return properties +} + +func (f *IoTTwinMakerComponentType) Remove(_ context.Context) error { + _, err := f.svc.DeleteComponentType(&iottwinmaker.DeleteComponentTypeInput{ + ComponentTypeId: f.ID, + WorkspaceId: f.workspaceID, + }) + + return err +} + +func (f *IoTTwinMakerComponentType) String() string { + return *f.ID +} diff --git a/resources/iottwinmaker-entity.go b/resources/iottwinmaker-entity.go new file mode 100644 index 00000000..ef3cbff3 --- /dev/null +++ b/resources/iottwinmaker-entity.go @@ -0,0 +1,124 @@ +package resources + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iottwinmaker" + + "github.com/ekristen/libnuke/pkg/registry" + "github.com/ekristen/libnuke/pkg/resource" + "github.com/ekristen/libnuke/pkg/types" + + "github.com/ekristen/aws-nuke/v3/pkg/nuke" +) + +const IoTTwinMakerEntityResource = "IoTTwinMakerEntity" + +func init() { + registry.Register(®istry.Registration{ + Name: IoTTwinMakerEntityResource, + Scope: nuke.Account, + Lister: &IoTTwinMakerEntityLister{}, + }) +} + +type IoTTwinMakerEntityLister struct{} + +func (l *IoTTwinMakerEntityLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { + opts := o.(*nuke.ListerOpts) + + svc := iottwinmaker.New(opts.Session) + resources := make([]resource.Resource, 0) + + // Require to have workspaces identifiers to query entities + workspaceListResponse, err := ListWorkspacesEntities(svc) + + if err != nil { + return nil, err + } + + for _, workspaceResponse := range workspaceListResponse { + params := &iottwinmaker.ListEntitiesInput{ + WorkspaceId: workspaceResponse.WorkspaceId, + MaxResults: aws.Int64(25), + } + + for { + resp, err := svc.ListEntities(params) + if err != nil { + return nil, err + } + + for _, item := range resp.EntitySummaries { + // We must filter out amazon-owned component types when querying tags, + // because their ARN format causes ListTagsForResource to vail with validation error + resources = append(resources, &IoTTwinMakerEntity{ + svc: svc, + ID: item.EntityId, + name: item.EntityName, + status: item.Status.State, + workspaceID: workspaceResponse.WorkspaceId, + }) + } + + if resp.NextToken == nil { + break + } + + params.NextToken = resp.NextToken + } + } + + return resources, nil +} + +// Utility function to list workspaces +func ListWorkspacesEntities(svc *iottwinmaker.IoTTwinMaker) ([]*iottwinmaker.WorkspaceSummary, error) { + resources := make([]*iottwinmaker.WorkspaceSummary, 0) + params := &iottwinmaker.ListWorkspacesInput{ + MaxResults: aws.Int64(25), + } + for { + resp, err := svc.ListWorkspaces(params) + if err != nil { + return nil, err + } + resources = append(resources, resp.WorkspaceSummaries...) + if resp.NextToken == nil { + break + } + params.NextToken = resp.NextToken + } + return resources, nil +} + +type IoTTwinMakerEntity struct { + svc *iottwinmaker.IoTTwinMaker + ID *string + name *string + status *string + workspaceID *string +} + +func (f *IoTTwinMakerEntity) Properties() types.Properties { + properties := types.NewProperties() + properties.Set("name", f.name) + properties.Set("status", f.status) + properties.Set("workspaceID", f.workspaceID) + return properties +} + +func (f *IoTTwinMakerEntity) Remove(_ context.Context) error { + _, err := f.svc.DeleteEntity(&iottwinmaker.DeleteEntityInput{ + EntityId: f.ID, + WorkspaceId: f.workspaceID, + IsRecursive: aws.Bool(true), + }) + + return err +} + +func (f *IoTTwinMakerEntity) String() string { + return *f.ID +} diff --git a/resources/iottwinmaker-scene.go b/resources/iottwinmaker-scene.go new file mode 100644 index 00000000..eaf611e1 --- /dev/null +++ b/resources/iottwinmaker-scene.go @@ -0,0 +1,115 @@ +package resources + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iottwinmaker" + + "github.com/ekristen/libnuke/pkg/registry" + "github.com/ekristen/libnuke/pkg/resource" + "github.com/ekristen/libnuke/pkg/types" + + "github.com/ekristen/aws-nuke/v3/pkg/nuke" +) + +const IoTTwinMakerSceneResource = "IoTTwinMakerScene" + +func init() { + registry.Register(®istry.Registration{ + Name: IoTTwinMakerSceneResource, + Scope: nuke.Account, + Lister: &IoTTwinMakerSceneLister{}, + }) +} + +type IoTTwinMakerSceneLister struct{} + +func (l *IoTTwinMakerSceneLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { + opts := o.(*nuke.ListerOpts) + + svc := iottwinmaker.New(opts.Session) + resources := make([]resource.Resource, 0) + + // Require to have workspaces identifiers to query scenes + workspaceListResponse, err := ListWorkspacesScene(svc) + + if err != nil { + return nil, err + } + + for _, workspaceResponse := range workspaceListResponse { + params := &iottwinmaker.ListScenesInput{ + WorkspaceId: workspaceResponse.WorkspaceId, + MaxResults: aws.Int64(25), + } + + for { + resp, err := svc.ListScenes(params) + if err != nil { + return nil, err + } + + for _, item := range resp.SceneSummaries { + resources = append(resources, &IoTTwinMakerScene{ + svc: svc, + ID: item.SceneId, + workspaceID: workspaceResponse.WorkspaceId, + }) + } + + if resp.NextToken == nil { + break + } + + params.NextToken = resp.NextToken + } + } + + return resources, nil +} + +// Utility function to list workspaces +func ListWorkspacesScene(svc *iottwinmaker.IoTTwinMaker) ([]*iottwinmaker.WorkspaceSummary, error) { + resources := make([]*iottwinmaker.WorkspaceSummary, 0) + params := &iottwinmaker.ListWorkspacesInput{ + MaxResults: aws.Int64(25), + } + for { + resp, err := svc.ListWorkspaces(params) + if err != nil { + return nil, err + } + resources = append(resources, resp.WorkspaceSummaries...) + if resp.NextToken == nil { + break + } + params.NextToken = resp.NextToken + } + return resources, nil +} + +type IoTTwinMakerScene struct { + svc *iottwinmaker.IoTTwinMaker + ID *string + workspaceID *string +} + +func (f *IoTTwinMakerScene) Properties() types.Properties { + properties := types.NewProperties() + properties.Set("workspaceID", f.workspaceID) + return properties +} + +func (f *IoTTwinMakerScene) Remove(_ context.Context) error { + _, err := f.svc.DeleteScene(&iottwinmaker.DeleteSceneInput{ + SceneId: f.ID, + WorkspaceId: f.workspaceID, + }) + + return err +} + +func (f *IoTTwinMakerScene) String() string { + return *f.ID +} diff --git a/resources/iottwinmaker-sync-job.go b/resources/iottwinmaker-sync-job.go new file mode 100644 index 00000000..af2355a2 --- /dev/null +++ b/resources/iottwinmaker-sync-job.go @@ -0,0 +1,117 @@ +package resources + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iottwinmaker" + + "github.com/ekristen/libnuke/pkg/registry" + "github.com/ekristen/libnuke/pkg/resource" + "github.com/ekristen/libnuke/pkg/types" + + "github.com/ekristen/aws-nuke/v3/pkg/nuke" +) + +const IoTTwinMakerSyncJobResource = "IoTTwinMakerSyncJob" + +func init() { + registry.Register(®istry.Registration{ + Name: IoTTwinMakerSyncJobResource, + Scope: nuke.Account, + Lister: &IoTTwinMakerSyncJobLister{}, + }) +} + +type IoTTwinMakerSyncJobLister struct{} + +func (l *IoTTwinMakerSyncJobLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { + opts := o.(*nuke.ListerOpts) + + svc := iottwinmaker.New(opts.Session) + resources := make([]resource.Resource, 0) + + // Require to have workspaces identifiers to query sync jobs + workspaceListResponse, err := ListWorkspacesSyncJob(svc) + + if err != nil { + return nil, err + } + + for _, workspaceResponse := range workspaceListResponse { + params := &iottwinmaker.ListSyncJobsInput{ + WorkspaceId: workspaceResponse.WorkspaceId, + MaxResults: aws.Int64(25), + } + + for { + resp, err := svc.ListSyncJobs(params) + if err != nil { + return nil, err + } + + for _, item := range resp.SyncJobSummaries { + resources = append(resources, &IoTTwinMakerSyncJob{ + svc: svc, + arn: item.Arn, + syncSource: item.SyncSource, + workspaceID: workspaceResponse.WorkspaceId, + }) + } + + if resp.NextToken == nil { + break + } + + params.NextToken = resp.NextToken + } + } + + return resources, nil +} + +// Utility function to list workspaces +func ListWorkspacesSyncJob(svc *iottwinmaker.IoTTwinMaker) ([]*iottwinmaker.WorkspaceSummary, error) { + resources := make([]*iottwinmaker.WorkspaceSummary, 0) + params := &iottwinmaker.ListWorkspacesInput{ + MaxResults: aws.Int64(25), + } + for { + resp, err := svc.ListWorkspaces(params) + if err != nil { + return nil, err + } + resources = append(resources, resp.WorkspaceSummaries...) + if resp.NextToken == nil { + break + } + params.NextToken = resp.NextToken + } + return resources, nil +} + +type IoTTwinMakerSyncJob struct { + svc *iottwinmaker.IoTTwinMaker + arn *string + syncSource *string + workspaceID *string +} + +func (f *IoTTwinMakerSyncJob) Properties() types.Properties { + properties := types.NewProperties() + properties.Set("workspaceID", f.workspaceID) + return properties +} + +func (f *IoTTwinMakerSyncJob) Remove(_ context.Context) error { + _, err := f.svc.DeleteSyncJob(&iottwinmaker.DeleteSyncJobInput{ + SyncSource: f.syncSource, + WorkspaceId: f.workspaceID, + }) + + return err +} + +func (f *IoTTwinMakerSyncJob) String() string { + return *f.arn +} diff --git a/resources/iottwinmaker-workspace.go b/resources/iottwinmaker-workspace.go new file mode 100644 index 00000000..5f17d6aa --- /dev/null +++ b/resources/iottwinmaker-workspace.go @@ -0,0 +1,101 @@ +package resources + +import ( + "context" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iottwinmaker" + + "github.com/ekristen/libnuke/pkg/registry" + "github.com/ekristen/libnuke/pkg/resource" + "github.com/ekristen/libnuke/pkg/types" + + "github.com/ekristen/aws-nuke/v3/pkg/nuke" +) + +const IoTTwinMakerWorkspaceResource = "IoTTwinMakerWorkspace" + +func init() { + registry.Register(®istry.Registration{ + Name: IoTTwinMakerWorkspaceResource, + Scope: nuke.Account, + Lister: &IoTTwinMakerWorkspaceLister{}, + DependsOn: []string{ + IoTTwinMakerComponentTypeResource, + IoTTwinMakerEntityResource, + IoTTwinMakerSceneResource, + IoTTwinMakerSyncJobResource, + }, + }) +} + +type IoTTwinMakerWorkspaceLister struct{} + +func (l *IoTTwinMakerWorkspaceLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) { + opts := o.(*nuke.ListerOpts) + + svc := iottwinmaker.New(opts.Session) + resources := make([]resource.Resource, 0) + + params := &iottwinmaker.ListWorkspacesInput{ + MaxResults: aws.Int64(25), + } + + for { + + resp, err := svc.ListWorkspaces(params) + if err != nil { + return nil, err + } + + for _, item := range resp.WorkspaceSummaries { + tagResp, err := svc.ListTagsForResource( + &iottwinmaker.ListTagsForResourceInput{ + ResourceARN: item.Arn, + }) + if err != nil { + return nil, err + } + + resources = append(resources, &IoTTwinMakerWorkspace{ + svc: svc, + ID: item.WorkspaceId, + tags: tagResp.Tags, + }) + } + + if resp.NextToken == nil { + break + } + + params.NextToken = resp.NextToken + } + + return resources, nil +} + +type IoTTwinMakerWorkspace struct { + svc *iottwinmaker.IoTTwinMaker + ID *string + tags map[string]*string +} + +func (f *IoTTwinMakerWorkspace) Properties() types.Properties { + properties := types.NewProperties() + for k, v := range f.tags { + properties.SetTag(&k, v) + } + return properties +} + +func (f *IoTTwinMakerWorkspace) Remove(_ context.Context) error { + _, err := f.svc.DeleteWorkspace(&iottwinmaker.DeleteWorkspaceInput{ + WorkspaceId: f.ID, + }) + + return err +} + +func (f *IoTTwinMakerWorkspace) String() string { + return *f.ID +}