mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
Merge pull request #20663 from thockin/svc-ctrl-defer-ip-release
Use defer for IP release
This commit is contained in:
commit
df6ac92976
@ -464,6 +464,12 @@ func (gce *GCECloud) EnsureLoadBalancer(name, region string, requestedIP net.IP,
|
||||
// function in order to maintain the invariant that "if the forwarding rule
|
||||
// exists, the LB has been fully created".
|
||||
ipAddress := ""
|
||||
// Through this process we try to keep track of whether it is safe to
|
||||
// release the IP that was allocated. If the user specifically asked for
|
||||
// an IP, we assume they are managing it themselves. Otherwise, we will
|
||||
// release the IP in case of early-terminating failure or upon successful
|
||||
// creating of the LB.
|
||||
releaseStaticIP := false
|
||||
if requestedIP != nil {
|
||||
// If a specific IP address has been requested, we have to respect the
|
||||
// user's request and use that IP. If the forwarding rule was already using
|
||||
@ -477,11 +483,34 @@ func (gce *GCECloud) EnsureLoadBalancer(name, region string, requestedIP net.IP,
|
||||
} else {
|
||||
// This will either allocate a new static IP if the forwarding rule didn't
|
||||
// already have an IP, or it will promote the forwarding rule's IP from
|
||||
// ephemeral to static.
|
||||
ipAddress, err = gce.createOrPromoteStaticIP(name, region, fwdRuleIP)
|
||||
// ephemeral to static, or it will just get the IP if it is already
|
||||
// static.
|
||||
existed := false
|
||||
ipAddress, existed, err = gce.ensureStaticIP(name, region, fwdRuleIP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existed {
|
||||
// If the IP was not specifically requested by the user, but it
|
||||
// already existed, it seems to be a failed update cycle. We can
|
||||
// use this IP and try to run through the process again, but we
|
||||
// should not release the IP unless it is explicitly flagged as OK.
|
||||
releaseStaticIP = false
|
||||
} else {
|
||||
// For total clarity. The IP did not pre-exist and the user did
|
||||
// not ask for a particular one, so we can release the IP in case
|
||||
// of failure or success.
|
||||
releaseStaticIP = true
|
||||
}
|
||||
defer func() {
|
||||
if releaseStaticIP {
|
||||
if err := gce.deleteStaticIP(name, region); err != nil {
|
||||
glog.Errorf("failed to release static IP %s during update of load balancer (%v, %v): %v", ipAddress, name, region, err)
|
||||
}
|
||||
} else {
|
||||
glog.Warningf("orphaning static IP %s during update of load balancer (%v, %v): %v", ipAddress, name, region, err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Deal with the firewall next. The reason we do this here rather than last
|
||||
@ -520,6 +549,10 @@ func (gce *GCECloud) EnsureLoadBalancer(name, region string, requestedIP net.IP,
|
||||
// Thus, we have to tear down the forwarding rule if either it or the target
|
||||
// pool needs to be updated.
|
||||
if fwdRuleExists && (fwdRuleNeedsUpdate || tpNeedsUpdate) {
|
||||
// Begin critical section. If we have to delete the forwarding rule,
|
||||
// and something should fail before we recreate it, don't release the
|
||||
// IP. That way we can come back to it later.
|
||||
releaseStaticIP = false
|
||||
if err := gce.deleteForwardingRule(name, region); err != nil {
|
||||
return nil, fmt.Errorf("failed to delete existing forwarding rule %s for load balancer update: %v", name, err)
|
||||
}
|
||||
@ -541,12 +574,10 @@ func (gce *GCECloud) EnsureLoadBalancer(name, region string, requestedIP net.IP,
|
||||
if err := gce.createForwardingRule(name, region, ipAddress, ports); err != nil {
|
||||
return nil, fmt.Errorf("failed to create forwarding rule %s: %v", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we're done operating on everything, demote the static IP back to
|
||||
// ephemeral to avoid taking up the user's static IP quota.
|
||||
if err := gce.deleteStaticIP(name, region); err != nil {
|
||||
return nil, fmt.Errorf("failed to release static IP %s after finishing update of load balancer resources: %v", err)
|
||||
// End critical section. It is safe to release the static IP (which
|
||||
// just demotes it to ephemeral) now that it is attached. In the case
|
||||
// of a user-requested IP, the 'defer' won't be installed anyway.
|
||||
releaseStaticIP = true
|
||||
}
|
||||
|
||||
status := &api.LoadBalancerStatus{}
|
||||
@ -857,32 +888,41 @@ func (gce *GCECloud) projectOwnsStaticIP(name, region string, ipAddress string)
|
||||
return fmt.Errorf("this gce project doesn't own the IP address: %s", ipAddress)
|
||||
}
|
||||
|
||||
func (gce *GCECloud) createOrPromoteStaticIP(name, region, existingIP string) (ipAddress string, err error) {
|
||||
func (gce *GCECloud) ensureStaticIP(name, region, existingIP string) (ipAddress string, created bool, err error) {
|
||||
// If the address doesn't exist, this will create it.
|
||||
// If the existingIP exists but is ephemeral, this will promote it to static.
|
||||
// If the address already exists, this will harmlessly return a StatusConflict
|
||||
// and we'll grab the IP before returning.
|
||||
existed := false
|
||||
addressObj := &compute.Address{Name: name}
|
||||
if existingIP != "" {
|
||||
addressObj.Address = existingIP
|
||||
}
|
||||
op, err := gce.service.Addresses.Insert(gce.projectID, region, addressObj).Do()
|
||||
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
||||
return "", fmt.Errorf("error creating gce static IP address: %v", err)
|
||||
if err != nil {
|
||||
if !isHTTPErrorCode(err, http.StatusConflict) {
|
||||
return "", false, fmt.Errorf("error creating gce static IP address: %v", err)
|
||||
}
|
||||
// StatusConflict == the IP exists already.
|
||||
existed = true
|
||||
}
|
||||
if op != nil {
|
||||
err := gce.waitForRegionOp(op, region)
|
||||
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
||||
return "", fmt.Errorf("error waiting for gce static IP address to be created: %v", err)
|
||||
if err != nil {
|
||||
if !isHTTPErrorCode(err, http.StatusConflict) {
|
||||
return "", false, fmt.Errorf("error waiting for gce static IP address to be created: %v", err)
|
||||
}
|
||||
// StatusConflict == the IP exists already.
|
||||
existed = true
|
||||
}
|
||||
}
|
||||
|
||||
// We have to get the address to know which IP was allocated for us.
|
||||
address, err := gce.service.Addresses.Get(gce.projectID, region, name).Do()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error re-getting gce static IP address: %v", err)
|
||||
return "", false, fmt.Errorf("error re-getting gce static IP address: %v", err)
|
||||
}
|
||||
return address.Address, nil
|
||||
return address.Address, existed, nil
|
||||
}
|
||||
|
||||
// UpdateLoadBalancer is an implementation of LoadBalancer.UpdateLoadBalancer.
|
||||
|
Loading…
Reference in New Issue
Block a user