func()

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
}