github.com/GoogleCloudPlatform/terraformer@v0.8.18/providers/aws/ebs.go (about)

     1  // Copyright 2019 The Terraformer Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package aws
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strings"
    21  
    22  	"github.com/GoogleCloudPlatform/terraformer/terraformutils"
    23  	"github.com/aws/aws-sdk-go-v2/aws"
    24  	"github.com/hashicorp/terraform/helper/hashcode"
    25  
    26  	"github.com/aws/aws-sdk-go-v2/service/ec2"
    27  	"github.com/aws/aws-sdk-go-v2/service/ec2/types"
    28  )
    29  
    30  var ebsAllowEmptyValues = []string{"tags."}
    31  
    32  type EbsGenerator struct {
    33  	AWSService
    34  }
    35  
    36  func (g *EbsGenerator) volumeAttachmentID(device, volumeID, instanceID string) string {
    37  	return fmt.Sprintf("vai-%d", hashcode.String(fmt.Sprintf("%s-%s-%s-", device, instanceID, volumeID)))
    38  }
    39  
    40  func (g *EbsGenerator) InitResources() error {
    41  	config, e := g.generateConfig()
    42  	if e != nil {
    43  		return e
    44  	}
    45  	svc := ec2.NewFromConfig(config)
    46  	var filters []types.Filter
    47  	for _, filter := range g.Filter {
    48  		if strings.HasPrefix(filter.FieldPath, "tags.") && filter.IsApplicable("ebs_volume") {
    49  			filters = append(filters, types.Filter{
    50  				Name:   aws.String("tag:" + strings.TrimPrefix(filter.FieldPath, "tags.")),
    51  				Values: filter.AcceptableValues,
    52  			})
    53  		}
    54  	}
    55  	p := ec2.NewDescribeVolumesPaginator(svc, &ec2.DescribeVolumesInput{
    56  		Filters: filters,
    57  	})
    58  	for p.HasMorePages() {
    59  		page, e := p.NextPage(context.TODO())
    60  		if e != nil {
    61  			return e
    62  		}
    63  		for _, volume := range page.Volumes {
    64  			isRootDevice := false // Let's leave root device configuration to be done in ec2_instance resources
    65  
    66  			for _, attachment := range volume.Attachments {
    67  				instances, _ := svc.DescribeInstances(context.TODO(), &ec2.DescribeInstancesInput{
    68  					InstanceIds: []string{StringValue(attachment.InstanceId)},
    69  				})
    70  				for _, reservation := range instances.Reservations {
    71  					for _, instance := range reservation.Instances {
    72  						if StringValue(instance.RootDeviceName) == StringValue(attachment.Device) {
    73  							isRootDevice = true
    74  						}
    75  					}
    76  				}
    77  			}
    78  
    79  			if !isRootDevice {
    80  				g.Resources = append(g.Resources, terraformutils.NewSimpleResource(
    81  					StringValue(volume.VolumeId),
    82  					StringValue(volume.VolumeId),
    83  					"aws_ebs_volume",
    84  					"aws",
    85  					ebsAllowEmptyValues,
    86  				))
    87  
    88  				for _, attachment := range volume.Attachments {
    89  					if attachment.State == types.VolumeAttachmentStateAttached {
    90  						attachmentID := g.volumeAttachmentID(
    91  							StringValue(attachment.Device),
    92  							StringValue(attachment.VolumeId),
    93  							StringValue(attachment.InstanceId))
    94  						g.Resources = append(g.Resources, terraformutils.NewResource(
    95  							attachmentID,
    96  							StringValue(attachment.InstanceId)+":"+StringValue(attachment.Device),
    97  							"aws_volume_attachment",
    98  							"aws",
    99  							map[string]string{
   100  								"device_name": StringValue(attachment.Device),
   101  								"volume_id":   StringValue(attachment.VolumeId),
   102  								"instance_id": StringValue(attachment.InstanceId),
   103  							},
   104  							[]string{},
   105  							map[string]interface{}{},
   106  						))
   107  					}
   108  				}
   109  			}
   110  		}
   111  	}
   112  	return nil
   113  }