in pkg/aws/ec2/api/helper.go [451:548]
func (h *ec2APIHelper) AssignIPv4ResourcesAndWaitTillReady(eniID string, resourceType config.ResourceType, count int) ([]string, error) {
var assignedResources []string
input := &ec2.AssignPrivateIpAddressesInput{}
count32, err := utils.IntToInt32(count)
if err != nil {
return nil, fmt.Errorf("invalid count: %v", err)
}
switch resourceType {
case config.ResourceTypeIPv4Address:
input = &ec2.AssignPrivateIpAddressesInput{
NetworkInterfaceId: &eniID,
SecondaryPrivateIpAddressCount: aws.Int32(count32),
}
case config.ResourceTypeIPv4Prefix:
input = &ec2.AssignPrivateIpAddressesInput{
NetworkInterfaceId: &eniID,
Ipv4PrefixCount: aws.Int32(count32),
}
}
assignPrivateIPOutput, err := h.ec2Wrapper.AssignPrivateIPAddresses(input)
if err != nil {
return assignedResources, err
}
if assignPrivateIPOutput == nil ||
(resourceType == config.ResourceNameIPAddress && len(assignPrivateIPOutput.AssignedPrivateIpAddresses) == 0) ||
(resourceType == config.ResourceTypeIPv4Prefix && len(assignPrivateIPOutput.AssignedIpv4Prefixes) == 0) {
return assignedResources, fmt.Errorf("failed to create %v %s to eni %s", count, resourceType, eniID)
}
ErrIPNotAttachedYet := fmt.Errorf("private IPv4 address is not attached yet")
ErrPrefixNotAttachedYet := fmt.Errorf("IPv4 prefix is not attached yet")
err = retry.OnError(waitForIPAttachment,
func(err error) bool {
if err == ErrIPNotAttachedYet || err == ErrPrefixNotAttachedYet {
// Retry in case IPv4 Resources are not attached yet
return true
}
return false
}, func() error {
// Describe the network interface on which the new IP or prefixes are assigned
interfaces, err := h.DescribeNetworkInterfaces([]string{eniID})
// Re-initialize the slice so that we don't add IP resources multiple times
assignedResources = []string{}
if err == nil && len(interfaces) == 1 {
if resourceType == config.ResourceTypeIPv4Address && interfaces[0].PrivateIpAddresses != nil {
// Get the map of IPs returned by the describe network interface call
ipAddress := map[string]bool{}
for _, ipAddr := range interfaces[0].PrivateIpAddresses {
ipAddress[*ipAddr.PrivateIpAddress] = true
}
// Verify describe network interface returns all the IPs that were assigned in the
// AssignPrivateIPAddresses call
for _, ip := range assignPrivateIPOutput.AssignedPrivateIpAddresses {
if _, ok := ipAddress[*ip.PrivateIpAddress]; !ok {
// Even if one IP is not assigned, set the error so that we only return only the IPs that
// are successfully assigned on the ENI
err = ErrIPNotAttachedYet
} else {
assignedResources = append(assignedResources, *ip.PrivateIpAddress)
}
}
return err
} else if resourceType == config.ResourceTypeIPv4Prefix && interfaces[0].Ipv4Prefixes != nil {
// Get the map of IP prefixes returned by the describe network interface call
ipPrefixes := map[string]bool{}
for _, ipPrefix := range interfaces[0].Ipv4Prefixes {
ipPrefixes[*ipPrefix.Ipv4Prefix] = true
}
// Verify describe network interface returns all the IP prefixes that were assigned in the
// AssignPrivateIPAddresses call
for _, prefix := range assignPrivateIPOutput.AssignedIpv4Prefixes {
if _, ok := ipPrefixes[*prefix.Ipv4Prefix]; !ok {
// Even if one prefix is not assigned, set the error so that we only return the IP prefixes that
// are successfully assigned on the ENI
err = ErrPrefixNotAttachedYet
} else {
assignedResources = append(assignedResources, *prefix.Ipv4Prefix)
}
}
return err
}
}
return err
})
if err != nil {
// If some of the assigned IP resources were not yet returned in the describe network interface call,
// returns the list of resources that were returned
return assignedResources, err
}
return assignedResources, nil
}