func()

in pkg/aws/ec2/api/cleanup/eni_cleanup.go [113:205]


func (e *ENICleaner) DeleteLeakedResources() error {
	var errors []error
	availableENIs := make(map[string]struct{})
	vpcrcAvailableCount := 0
	vpccniAvailableCount := 0
	leakedENICount := 0
	defer e.Manager.UpdateCleanupMetrics(&vpcrcAvailableCount, &vpccniAvailableCount, &leakedENICount)

	filters := append(CommonNetworkInterfaceFilters, []ec2types.Filter{
		{
			Name:   aws.String("vpc-id"),
			Values: []string{e.VpcId},
		},
	}...)

	// only apply extra filters when the controller is enabled which provides cninode resources
	var OrFilters []ec2types.Filter
	var err error
	var networkInterfaces []*ec2types.NetworkInterface
	if !e.ControllerDisabled {
		// get cleaner specific filters
		OrFilters = e.Manager.GetENITagFilters()
		for _, OrFilter := range OrFilters {
			filterCopy := append([]ec2types.Filter{}, filters...)
			filterCopy = append(filterCopy, OrFilter)

			describeNetworkInterfaceIp := &ec2.DescribeNetworkInterfacesInput{
				Filters: filterCopy,
			}

			tempNetworkInterfaces, err := e.EC2Wrapper.DescribeNetworkInterfacesPagesWithRetry(describeNetworkInterfaceIp)
			if err != nil {
				e.Log.Error(err, "failed to describe network interfaces, cleanup will be retried in next cycle")
				return err
			}
			networkInterfaces = append(networkInterfaces, tempNetworkInterfaces...)
		}
	} else {
		describeNetworkInterfaceIp := &ec2.DescribeNetworkInterfacesInput{
			Filters: filters,
		}
		networkInterfaces, err = e.EC2Wrapper.DescribeNetworkInterfacesPagesWithRetry(describeNetworkInterfaceIp)
		if err != nil {
			e.Log.Error(err, "failed to describe network interfaces, cleanup will be retried in next cycle")
			return err
		}
	}

	for _, nwInterface := range networkInterfaces {
		if e.Manager.ShouldDeleteENI(nwInterface.NetworkInterfaceId) {
			tagMap := utils.GetTagKeyValueMap(nwInterface.TagSet)
			if val, ok := tagMap[config.NetworkInterfaceOwnerTagKey]; ok {
				// Increment promethues metrics for number of leaked ENIs cleaned up
				switch val {
				case config.NetworkInterfaceOwnerTagValue:
					vpcrcAvailableCount += 1
				case config.NetworkInterfaceOwnerVPCCNITagValue:
					vpccniAvailableCount += 1
				default:
					// We should not hit this case as we only filter for relevant tag values, log error and continue if unexpected ENIs found
					e.Log.Error(fmt.Errorf("found available ENI not created by VPC-CNI/VPC-RC"), "eniID", *nwInterface.NetworkInterfaceId)
					continue
				}
			}
			_, err := e.EC2Wrapper.DeleteNetworkInterface(&ec2.DeleteNetworkInterfaceInput{
				NetworkInterfaceId: nwInterface.NetworkInterfaceId,
			})
			if err != nil {
				if !strings.Contains(err.Error(), ec2Errors.NotFoundInterfaceID) { // ignore InvalidNetworkInterfaceID.NotFound error
					// append err and continue, we will retry deletion in the next period/reconcile
					leakedENICount += 1
					errors = append(errors, fmt.Errorf("failed to delete leaked network interface %v:%v", *nwInterface.NetworkInterfaceId, err))
					e.Log.Error(err, "failed to delete the leaked network interface",
						"id", *nwInterface.NetworkInterfaceId)
				}
				continue
			}
			// It is possible for eni attachment to be nil, if it was never attached to instance
			instanceID := ""
			if nwInterface.Attachment != nil && nwInterface.Attachment.InstanceId != nil {
				instanceID = aws.ToString(nwInterface.Attachment.InstanceId)
			}
			e.Log.Info("deleted leaked ENI successfully", "eni id", *nwInterface.NetworkInterfaceId, "instance id", instanceID)
		} else {
			// Seeing the ENI for the first time, add it to the new list of available network interfaces
			availableENIs[*nwInterface.NetworkInterfaceId] = struct{}{}
			e.Log.Info("adding eni to to the map of available ENIs, will be removed if present in "+
				"next run too", "id", *nwInterface.NetworkInterfaceId)
		}
	}
	e.Manager.UpdateAvailableENIsIfNeeded(&availableENIs)
	return kerrors.NewAggregate(errors)
}