terraform/builtin/providers/aws/import_aws_security_group.go

187 lines
5.3 KiB
Go

package aws
import (
"fmt"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/helper/schema"
)
// Security group import fans out to multiple resources due to the
// security group rules. Instead of creating one resource with nested
// rules, we use the best practices approach of one resource per rule.
func resourceAwsSecurityGroupImportState(
d *schema.ResourceData,
meta interface{}) ([]*schema.ResourceData, error) {
conn := meta.(*AWSClient).ec2conn
// First query the security group
sgRaw, _, err := SGStateRefreshFunc(conn, d.Id())()
if err != nil {
return nil, err
}
if sgRaw == nil {
return nil, fmt.Errorf("security group not found")
}
sg := sgRaw.(*ec2.SecurityGroup)
// Start building our results
results := make([]*schema.ResourceData, 1,
1+len(sg.IpPermissions)+len(sg.IpPermissionsEgress))
results[0] = d
// Construct the rules
permMap := map[string][]*ec2.IpPermission{
"ingress": sg.IpPermissions,
"egress": sg.IpPermissionsEgress,
}
for ruleType, perms := range permMap {
for _, perm := range perms {
ds, err := resourceAwsSecurityGroupImportStatePerm(sg, ruleType, perm)
if err != nil {
return nil, err
}
results = append(results, ds...)
}
}
return results, nil
}
func resourceAwsSecurityGroupImportStatePerm(sg *ec2.SecurityGroup, ruleType string, perm *ec2.IpPermission) ([]*schema.ResourceData, error) {
/*
Create a seperate Security Group Rule for:
* The collection of IpRanges (cidr_blocks)
* The collection of Ipv6Ranges (ipv6_cidr_blocks)
* Each individual UserIdGroupPair (source_security_group_id)
If, for example, a security group has rules for:
* 2 IpRanges
* 2 Ipv6Ranges
* 2 UserIdGroupPairs
This would generate 4 security group rules:
* 1 for the collection of IpRanges
* 1 for the collection of Ipv6Ranges
* 1 for the first UserIdGroupPair
* 1 for the second UserIdGroupPair
*/
var result []*schema.ResourceData
if perm.IpRanges != nil {
p := &ec2.IpPermission{
FromPort: perm.FromPort,
IpProtocol: perm.IpProtocol,
PrefixListIds: perm.PrefixListIds,
ToPort: perm.ToPort,
IpRanges: perm.IpRanges,
}
r, err := resourceAwsSecurityGroupImportStatePermPair(sg, ruleType, p)
if err != nil {
return nil, err
}
result = append(result, r)
}
if perm.Ipv6Ranges != nil {
p := &ec2.IpPermission{
FromPort: perm.FromPort,
IpProtocol: perm.IpProtocol,
PrefixListIds: perm.PrefixListIds,
ToPort: perm.ToPort,
Ipv6Ranges: perm.Ipv6Ranges,
}
r, err := resourceAwsSecurityGroupImportStatePermPair(sg, ruleType, p)
if err != nil {
return nil, err
}
result = append(result, r)
}
if len(perm.UserIdGroupPairs) > 0 {
for _, pair := range perm.UserIdGroupPairs {
p := &ec2.IpPermission{
FromPort: perm.FromPort,
IpProtocol: perm.IpProtocol,
PrefixListIds: perm.PrefixListIds,
ToPort: perm.ToPort,
UserIdGroupPairs: []*ec2.UserIdGroupPair{pair},
}
r, err := resourceAwsSecurityGroupImportStatePermPair(sg, ruleType, p)
if err != nil {
return nil, err
}
result = append(result, r)
}
}
if len(result) == 0 && len(perm.PrefixListIds) > 0 {
p := &ec2.IpPermission{
FromPort: perm.FromPort,
IpProtocol: perm.IpProtocol,
PrefixListIds: perm.PrefixListIds,
ToPort: perm.ToPort,
}
r, err := resourceAwsSecurityGroupImportStatePermPair(sg, ruleType, p)
if err != nil {
return nil, err
}
result = append(result, r)
}
return result, nil
}
func resourceAwsSecurityGroupImportStatePermPair(sg *ec2.SecurityGroup, ruleType string, perm *ec2.IpPermission) (*schema.ResourceData, error) {
// Construct the rule. We do this by populating the absolute
// minimum necessary for Refresh on the rule to work. This
// happens to be a lot of fields since they're almost all needed
// for de-dupping.
sgId := sg.GroupId
id := ipPermissionIDHash(*sgId, ruleType, perm)
ruleResource := resourceAwsSecurityGroupRule()
d := ruleResource.Data(nil)
d.SetId(id)
d.SetType("aws_security_group_rule")
d.Set("security_group_id", sgId)
d.Set("type", ruleType)
// 'self' is false by default. Below, we range over the group ids and set true
// if the parent sg id is found
d.Set("self", false)
if len(perm.UserIdGroupPairs) > 0 {
s := perm.UserIdGroupPairs[0]
// Check for Pair that is the same as the Security Group, to denote self.
// Otherwise, mark the group id in source_security_group_id
isVPC := sg.VpcId != nil && *sg.VpcId != ""
if isVPC {
if *s.GroupId == *sg.GroupId {
d.Set("self", true)
// prune the self reference from the UserIdGroupPairs, so we don't
// have duplicate sg ids (both self and in source_security_group_id)
perm.UserIdGroupPairs = append(perm.UserIdGroupPairs[:0], perm.UserIdGroupPairs[0+1:]...)
}
} else {
if *s.GroupName == *sg.GroupName {
d.Set("self", true)
// prune the self reference from the UserIdGroupPairs, so we don't
// have duplicate sg ids (both self and in source_security_group_id)
perm.UserIdGroupPairs = append(perm.UserIdGroupPairs[:0], perm.UserIdGroupPairs[0+1:]...)
}
}
}
if err := setFromIPPerm(d, sg, perm); err != nil {
return nil, errwrap.Wrapf("Error importing AWS Security Group: {{err}}", err)
}
return d, nil
}