func (e *Impl) UnassociateEipAddress(ctx context.Context, eipID, eniID, eniIP string) error {
	var innerErr error
	err := wait.ExponentialBackoff(ENIOpBackoff,
		func() (done bool, err error) {
			var eips []vpc.EipAddress
			eips, innerErr = e.describeEipAddresses(eipID, "")
			if innerErr != nil {
				return false, nil
			}
			if len(eips) == 0 {
				return true, nil
			}
			eip := eips[0]
			if eip.InstanceId != eniID {
				return true, nil
			}
			if eip.PrivateIpAddress != "" {
				if eniIP != eip.PrivateIpAddress {
					return true, nil
				}
			}
			innerErr = e.unAssociateEIPAddress(eipID, eniID, eniIP)
			if innerErr != nil {
				return false, nil
			}
			return true, nil
		},
	)
	if err != nil {
		return fmt.Errorf("error unassociate eip address: %v, %v, %v,%v,%w", eipID, eniID, eniIP, innerErr, err)
	}
	return nil
}
UnassociateEipAddress un associate eip
1. if eni is deleted eip auto unassociated
2. if eip is deleted , return code is InvalidAllocationId.NotFound
3. if eip is not bind ,return code is IncorrectEipStatus
package aliyun
import (
	"context"
	"fmt"
	"net"
	"strconv"
	"time"
	apiErr "github.com/AliyunContainerService/terway/pkg/aliyun/errors"
	"github.com/AliyunContainerService/terway/pkg/ip"
	"github.com/AliyunContainerService/terway/pkg/metric"
	"github.com/AliyunContainerService/terway/types"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/vpc"
	"github.com/sirupsen/logrus"
	"k8s.io/apimachinery/pkg/util/wait"
)
func (e *Impl) AllocateEipAddress(ctx context.Context, bandwidth int, chargeType types.InternetChargeType, eipID, eniID string, eniIP net.IP, allowRob bool) (*types.EIP, error) {
	var (
		eipInfo *types.EIP
		err     error
	)
	var eni *ecs.NetworkInterfaceSet
	eni, err = e.WaitForNetworkInterface(ctx, eniID, "", ENIOpBackoff, false)
	if err != nil {
		return nil, err
	}
	eipBindedPrivateIP := eniIP.String()
	if eni.PrivateIpAddress == eniIP.String() {
		eipBindedPrivateIP = ""
	}
	if eipID == "" {
		var eips []vpc.EipAddress
		eips, err = e.describeEipAddresses("", eniID)
		if err != nil {
			return nil, err
		}
		if len(eips) > 0 {
			for _, eip := range eips {
				if eip.PrivateIpAddress == eipBindedPrivateIP {
					publicIP, err := ip.ToIP(eip.IpAddress)
					if err != nil {
						return nil, fmt.Errorf("eip %s, %w", eip.AllocationId, err)
					}
					log.WithFields(map[string]interface{}{
						LogFieldEIPID:     eip.AllocationId,
						LogFieldENIID:     eniID,
						LogFieldPrivateIP: eniIP,
					}).Infof("resuse binded eip")
					return &types.EIP{
						ID:             eip.AllocationId,
						Address:        publicIP,
						AssociateENI:   eniID,
						AssociateENIIP: eniIP,
					}, nil
				}
			}
		}
		var resp *vpc.AllocateEipAddressResponse
		resp, err = e.allocateEIPAddress(strconv.Itoa(bandwidth), string(chargeType))
		if err != nil {
			return nil, err
		}
		eipAddress := net.ParseIP(resp.EipAddress)
		if eipAddress == nil {
			return nil, fmt.Errorf("invalid eip address %s, %s", resp.AllocationId, resp.EipAddress)
		}
		eipInfo = &types.EIP{
			ID:             resp.AllocationId,
			Address:        eipAddress,
			Delete:         true,
			AssociateENI:   eniID,
			AssociateENIIP: eniIP,
		}
		defer func() {
			if err != nil {
				err = e.ReleaseEipAddress(ctx, eipInfo.ID, eniID, eniIP)
				if err != nil {
					log.Errorf("error rollback eip: %+v, %+v, may cause eip leak...", resp.AllocationId, resp.EipAddress)
				}
			}
		}()
	} else {
		var eips []vpc.EipAddress
		eips, err = e.describeEipAddresses(eipID, "")
		if err != nil {
			return nil, err
		}
		if len(eips) == 0 {
			return nil, fmt.Errorf("can not found eip %s", eipID)
		}
		eip := eips[0]
		var eipAddress net.IP
		eipAddress, err = ip.ToIP(eip.IpAddress)
		if err != nil {
			return nil, fmt.Errorf("eip %s, %w", eip.AllocationId, err)
		}
		eipInfo = &types.EIP{
			ID:             eipID,
			Address:        eipAddress,
			AssociateENI:   eniID,
			AssociateENIIP: eniIP,
		}
		if eip.InstanceId == eniID &&
			eip.PrivateIpAddress == eipBindedPrivateIP {
			return eipInfo, nil
		}
		if allowRob && eip.Status == eipStatusInUse {
			err = e.unAssociateEIPAddress(eipID, "", "")
			if err != nil {
				return nil, fmt.Errorf("error unassocicate previous eip address, %v", err)
			}
			time.Sleep(3 * time.Second)
			start := time.Now()
			_, err = e.WaitForEIP(eipID, eipStatusAvailable, eniStateBackoff)
			metric.OpenAPILatency.WithLabelValues("UnassociateEipAddress/Async", fmt.Sprint(err != nil)).Observe(metric.MsSince(start))
			if err != nil {
				return nil, fmt.Errorf("error wait for eip to status Available: %v", err)
			}
		} else if eip.Status != eipStatusAvailable {
			err = fmt.Errorf("eip id: %v status is not Available", eipID)
			return nil, err
		}
	}
	logrus.Debugf("get eip info: %+v", eipInfo)
	err = e.associateEIPAddress(eipInfo.ID, eniID, eniIP.String())
	if err != nil {
		err = fmt.Errorf("error associate eip:%v to eni:%v.%v, err: %v", eipInfo, eniID, eniIP, err)
		return nil, err
	}
	time.Sleep(3 * time.Second)
	start := time.Now()
	_, err = e.WaitForEIP(eipInfo.ID, "InUse", eniStateBackoff)
	metric.OpenAPILatency.WithLabelValues("AssociateEipAddress/Async", fmt.Sprint(err != nil)).Observe(metric.MsSince(start))
	if err != nil {
		return nil, fmt.Errorf("wait for eip error: %v", err)
	}
	return eipInfo, nil
}