package middlewares import ( "github.com/sirupsen/logrus" "github.com/cloudskiff/driftctl/pkg/resource" "github.com/cloudskiff/driftctl/pkg/resource/aws" ) // Remove root_block_device from aws_instance resources and create dedicated aws_ebs_volume resources type AwsInstanceBlockDeviceResourceMapper struct { resourceFactory resource.ResourceFactory } func NewAwsInstanceBlockDeviceResourceMapper(resourceFactory resource.ResourceFactory) AwsInstanceBlockDeviceResourceMapper { return AwsInstanceBlockDeviceResourceMapper{ resourceFactory: resourceFactory, } } func (a AwsInstanceBlockDeviceResourceMapper) Execute(remoteResources, resourcesFromState *[]*resource.Resource) error { newStateResources := make([]*resource.Resource, 0) for _, stateRes := range *resourcesFromState { // Ignore all resources other than aws_instance if stateRes.ResourceType() != aws.AwsInstanceResourceType { newStateResources = append(newStateResources, stateRes) continue } if rootBlockDevice, exist := stateRes.Attrs.Get("root_block_device"); exist { for _, rootBlock := range rootBlockDevice.([]interface{}) { rootBlock := rootBlock.(map[string]interface{}) logrus.WithFields(logrus.Fields{ "volume": rootBlock["volume_id"], "instance": stateRes.ResourceId(), }).Debug("Creating aws_ebs_volume from aws_instance.root_block_device") data := map[string]interface{}{ "availability_zone": (*stateRes.Attrs)["availability_zone"], "encrypted": rootBlock["encrypted"], "id": rootBlock["volume_id"], "iops": rootBlock["iops"], "kms_key_id": rootBlock["kms_key_id"], "size": rootBlock["volume_size"], "type": rootBlock["volume_type"], "multi_attach_enabled": false, "tags": a.volumeTags(stateRes, rootBlock), } if throughput, exist := rootBlock["throughput"]; exist { data["throughput"] = throughput } newRes := a.resourceFactory.CreateAbstractResource("aws_ebs_volume", rootBlock["volume_id"].(string), data) newStateResources = append(newStateResources, newRes) } stateRes.Attrs.SafeDelete([]string{"root_block_device"}) stateRes.Attrs.SafeDelete([]string{"volume_tags"}) } if ebsBlockDevice, exist := stateRes.Attrs.Get("ebs_block_device"); exist { for _, blockDevice := range ebsBlockDevice.([]interface{}) { blockDevice := blockDevice.(map[string]interface{}) if a.hasBlockDevice(blockDevice, resourcesFromState) { continue } logrus.WithFields(logrus.Fields{ "volume": blockDevice["volume_id"], "instance": stateRes.ResourceId(), }).Debug("Creating aws_ebs_volume from aws_instance.ebs_block_device") data := map[string]interface{}{ "availability_zone": (*stateRes.Attrs)["availability_zone"], "encrypted": blockDevice["encrypted"], "id": blockDevice["volume_id"], "iops": blockDevice["iops"], "kms_key_id": blockDevice["kms_key_id"], "size": blockDevice["volume_size"], "type": blockDevice["volume_type"], "multi_attach_enabled": false, "tags": a.volumeTags(stateRes, blockDevice), } if throughput, exist := blockDevice["throughput"]; exist { data["throughput"] = throughput } newRes := a.resourceFactory.CreateAbstractResource("aws_ebs_volume", blockDevice["volume_id"].(string), data) newStateResources = append(newStateResources, newRes) } stateRes.Attrs.SafeDelete([]string{"ebs_block_device"}) stateRes.Attrs.SafeDelete([]string{"volume_tags"}) } newStateResources = append(newStateResources, stateRes) } newRemoteResources := make([]*resource.Resource, 0) for _, remoteRes := range *remoteResources { if remoteRes.ResourceType() != aws.AwsInstanceResourceType { newRemoteResources = append(newRemoteResources, remoteRes) continue } remoteRes.Attrs.SafeDelete([]string{"root_block_device"}) remoteRes.Attrs.SafeDelete([]string{"ebs_block_device"}) remoteRes.Attrs.SafeDelete([]string{"volume_tags"}) newRemoteResources = append(newRemoteResources, remoteRes) } *resourcesFromState = newStateResources *remoteResources = newRemoteResources return nil } func (a AwsInstanceBlockDeviceResourceMapper) volumeTags(instance *resource.Resource, blockDevice map[string]interface{}) interface{} { if tags, exist := instance.Attrs.Get("volume_tags"); exist { return tags } return blockDevice["tags"] } func (a AwsInstanceBlockDeviceResourceMapper) hasBlockDevice(blockDevice map[string]interface{}, resourcesFromState *[]*resource.Resource) bool { for _, stateRes := range *resourcesFromState { if stateRes.ResourceType() == aws.AwsEbsVolumeResourceType && stateRes.ResourceId() == blockDevice["volume_id"] { return true } } return false }