diff --git a/spinifex/handlers/ec2/vpc/service_impl.go b/spinifex/handlers/ec2/vpc/service_impl.go index 28b6ee932..c86873219 100644 --- a/spinifex/handlers/ec2/vpc/service_impl.go +++ b/spinifex/handlers/ec2/vpc/service_impl.go @@ -13,6 +13,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/spinifex/spinifex/arn" "github.com/mulgadc/spinifex/spinifex/awserrors" "github.com/mulgadc/spinifex/spinifex/config" "github.com/mulgadc/spinifex/spinifex/filterutil" @@ -132,6 +133,15 @@ func (s *VPCServiceImpl) localAZ() string { return s.config.AZ } +// region returns the configured AWS region, falling back to the default when +// no config or region is wired. +func (s *VPCServiceImpl) region() string { + if s.config == nil || s.config.Region == "" { + return config.DefaultAWSRegion + } + return s.config.Region +} + // NewVPCServiceImplWithNATS creates a VPC service with NATS JetStream for persistence. func NewVPCServiceImplWithNATS(ctx context.Context, cfg *config.Config, natsConn *nats.Conn) (*VPCServiceImpl, error) { js, err := jetstream.New(natsConn) @@ -1265,6 +1275,18 @@ func (s *VPCServiceImpl) subnetRecordToEC2(record *SubnetRecord, availableIPs in AvailableIpAddressCount: aws.Int64(int64(availableIPs)), OwnerId: aws.String(accountID), MapPublicIpOnLaunch: aws.Bool(record.MapPublicIpOnLaunch), + SubnetArn: aws.String(arn.FormatEC2(arn.EC2Subnet, s.region(), accountID, record.SubnetId)), + // Spinifex subnets are IPv4-only with no customer-owned pool, and + // instances are named ip- with no resource-name records. + AssignIpv6AddressOnCreation: aws.Bool(false), + EnableDns64: aws.Bool(false), + Ipv6Native: aws.Bool(false), + MapCustomerOwnedIpOnLaunch: aws.Bool(false), + PrivateDnsNameOptionsOnLaunch: &ec2.PrivateDnsNameOptionsOnLaunch{ + HostnameType: aws.String(ec2.HostnameTypeIpName), + EnableResourceNameDnsARecord: aws.Bool(false), + EnableResourceNameDnsAAAARecord: aws.Bool(false), + }, } subnet.Tags = utils.MapToEC2Tags(record.Tags) diff --git a/spinifex/handlers/ec2/vpc/service_impl_test.go b/spinifex/handlers/ec2/vpc/service_impl_test.go index 446b5dba4..e8f92c02b 100644 --- a/spinifex/handlers/ec2/vpc/service_impl_test.go +++ b/spinifex/handlers/ec2/vpc/service_impl_test.go @@ -287,6 +287,44 @@ func TestCreateSubnet(t *testing.T) { assert.Equal(t, int64(251), *out.Subnet.AvailableIpAddressCount) } +// TestSubnetResponse_AWSDefaultFields checks the ARN and the fields AWS +// reports for a new subnet, on both the create and describe paths. +func TestSubnetResponse_AWSDefaultFields(t *testing.T) { + t.Parallel() + svc := setupTestVPCService(t) + svc.config = &config.Config{Region: "ap-southeast-2"} + vpcID := createTestVPC(t, svc, "10.0.0.0/16") + + out, err := svc.CreateSubnet(context.Background(), &ec2.CreateSubnetInput{ + VpcId: aws.String(vpcID), + CidrBlock: aws.String("10.0.1.0/24"), + }, testAccountID) + require.NoError(t, err) + desc, err := svc.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{ + SubnetIds: []*string{out.Subnet.SubnetId}, + }, testAccountID) + require.NoError(t, err) + require.Len(t, desc.Subnets, 1) + + for name, subnet := range map[string]*ec2.Subnet{"create": out.Subnet, "describe": desc.Subnets[0]} { + assert.Equal(t, "arn:aws:ec2:ap-southeast-2:"+testAccountID+":subnet/"+*out.Subnet.SubnetId, aws.StringValue(subnet.SubnetArn), name) + for field, v := range map[string]*bool{ + "AssignIpv6AddressOnCreation": subnet.AssignIpv6AddressOnCreation, + "EnableDns64": subnet.EnableDns64, + "Ipv6Native": subnet.Ipv6Native, + "MapCustomerOwnedIpOnLaunch": subnet.MapCustomerOwnedIpOnLaunch, + } { + require.NotNil(t, v, "%s %s", name, field) + assert.False(t, *v, "%s %s", name, field) + } + assert.Equal(t, &ec2.PrivateDnsNameOptionsOnLaunch{ + HostnameType: aws.String("ip-name"), + EnableResourceNameDnsARecord: aws.Bool(false), + EnableResourceNameDnsAAAARecord: aws.Bool(false), + }, subnet.PrivateDnsNameOptionsOnLaunch, name) + } +} + func TestCreateSubnet_MissingVpcId(t *testing.T) { t.Parallel() svc := setupTestVPCService(t)