k8s.io/kubernetes@v1.29.3/pkg/proxy/ipvs/graceful_termination.go (about)

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package ipvs
    18  
    19  import (
    20  	"fmt"
    21  	"sync"
    22  	"time"
    23  
    24  	"k8s.io/apimachinery/pkg/util/wait"
    25  	"k8s.io/klog/v2"
    26  	utilipvs "k8s.io/kubernetes/pkg/proxy/ipvs/util"
    27  )
    28  
    29  const (
    30  	rsCheckDeleteInterval = 1 * time.Minute
    31  )
    32  
    33  // listItem stores real server information and the process time.
    34  // If nothing special happened, real server will be delete after process time.
    35  type listItem struct {
    36  	VirtualServer *utilipvs.VirtualServer
    37  	RealServer    *utilipvs.RealServer
    38  }
    39  
    40  // String return the unique real server name(with virtual server information)
    41  func (g *listItem) String() string {
    42  	return GetUniqueRSName(g.VirtualServer, g.RealServer)
    43  }
    44  
    45  // GetUniqueRSName return a string type unique rs name with vs information
    46  func GetUniqueRSName(vs *utilipvs.VirtualServer, rs *utilipvs.RealServer) string {
    47  	return vs.String() + "/" + rs.String()
    48  }
    49  
    50  type graceTerminateRSList struct {
    51  	lock sync.Mutex
    52  	list map[string]*listItem
    53  }
    54  
    55  // add push an new element to the rsList
    56  func (q *graceTerminateRSList) add(rs *listItem) bool {
    57  	q.lock.Lock()
    58  	defer q.lock.Unlock()
    59  
    60  	uniqueRS := rs.String()
    61  	if _, ok := q.list[uniqueRS]; ok {
    62  		return false
    63  	}
    64  
    65  	klog.V(5).InfoS("Adding real server to graceful delete real server list", "realServer", rs)
    66  	q.list[uniqueRS] = rs
    67  	return true
    68  }
    69  
    70  // remove remove an element from the rsList
    71  func (q *graceTerminateRSList) remove(rs *listItem) bool {
    72  	q.lock.Lock()
    73  	defer q.lock.Unlock()
    74  
    75  	uniqueRS := rs.String()
    76  	if _, ok := q.list[uniqueRS]; ok {
    77  		delete(q.list, uniqueRS)
    78  		return true
    79  	}
    80  	return false
    81  }
    82  
    83  // return the size of the list
    84  func (q *graceTerminateRSList) len() int {
    85  	q.lock.Lock()
    86  	defer q.lock.Unlock()
    87  
    88  	return len(q.list)
    89  }
    90  
    91  func (q *graceTerminateRSList) flushList(handler func(rsToDelete *listItem) (bool, error)) bool {
    92  	q.lock.Lock()
    93  	defer q.lock.Unlock()
    94  	success := true
    95  	for name, rs := range q.list {
    96  		deleted, err := handler(rs)
    97  		if err != nil {
    98  			klog.ErrorS(err, "Error in deleting real server", "realServer", name)
    99  			success = false
   100  		}
   101  		if deleted {
   102  			klog.InfoS("Removed real server from graceful delete real server list", "realServer", name)
   103  			delete(q.list, rs.String())
   104  		}
   105  	}
   106  	return success
   107  }
   108  
   109  // exist check whether the specified unique RS is in the rsList
   110  func (q *graceTerminateRSList) exist(uniqueRS string) (*listItem, bool) {
   111  	q.lock.Lock()
   112  	defer q.lock.Unlock()
   113  
   114  	if rs, ok := q.list[uniqueRS]; ok {
   115  		return rs, true
   116  	}
   117  	return nil, false
   118  }
   119  
   120  // GracefulTerminationManager manage rs graceful termination information and do graceful termination work
   121  // rsList is the rs list to graceful termination, ipvs is the ipvsinterface to do ipvs delete/update work
   122  type GracefulTerminationManager struct {
   123  	rsList graceTerminateRSList
   124  	ipvs   utilipvs.Interface
   125  }
   126  
   127  // NewGracefulTerminationManager create a gracefulTerminationManager to manage ipvs rs graceful termination work
   128  func NewGracefulTerminationManager(ipvs utilipvs.Interface) *GracefulTerminationManager {
   129  	l := make(map[string]*listItem)
   130  	return &GracefulTerminationManager{
   131  		rsList: graceTerminateRSList{
   132  			list: l,
   133  		},
   134  		ipvs: ipvs,
   135  	}
   136  }
   137  
   138  // InTerminationList to check whether specified unique rs name is in graceful termination list
   139  func (m *GracefulTerminationManager) InTerminationList(uniqueRS string) bool {
   140  	_, exist := m.rsList.exist(uniqueRS)
   141  	return exist
   142  }
   143  
   144  // GracefulDeleteRS to update rs weight to 0, and add rs to graceful terminate list
   145  func (m *GracefulTerminationManager) GracefulDeleteRS(vs *utilipvs.VirtualServer, rs *utilipvs.RealServer) error {
   146  	// Try to delete rs before add it to graceful delete list
   147  	ele := &listItem{
   148  		VirtualServer: vs,
   149  		RealServer:    rs,
   150  	}
   151  	deleted, err := m.deleteRsFunc(ele)
   152  	if err != nil {
   153  		klog.ErrorS(err, "Error in deleting real server", "realServer", ele)
   154  	}
   155  	if deleted {
   156  		return nil
   157  	}
   158  	rs.Weight = 0
   159  	err = m.ipvs.UpdateRealServer(vs, rs)
   160  	if err != nil {
   161  		return err
   162  	}
   163  	klog.V(5).InfoS("Adding real server to graceful delete real server list", "realServer", ele)
   164  	m.rsList.add(ele)
   165  	return nil
   166  }
   167  
   168  func (m *GracefulTerminationManager) deleteRsFunc(rsToDelete *listItem) (bool, error) {
   169  	klog.V(5).InfoS("Trying to delete real server", "realServer", rsToDelete)
   170  	rss, err := m.ipvs.GetRealServers(rsToDelete.VirtualServer)
   171  	if err != nil {
   172  		return false, err
   173  	}
   174  	for _, rs := range rss {
   175  		if rsToDelete.RealServer.Equal(rs) {
   176  			// For UDP and SCTP traffic, no graceful termination, we immediately delete the RS
   177  			//     (existing connections will be deleted on the next packet because sysctlExpireNoDestConn=1)
   178  			// For other protocols, don't delete until all connections have expired)
   179  			if utilipvs.IsRsGracefulTerminationNeeded(rsToDelete.VirtualServer.Protocol) && rs.ActiveConn+rs.InactiveConn != 0 {
   180  				klog.V(5).InfoS("Skip deleting real server till all connection have expired", "realServer", rsToDelete, "activeConnection", rs.ActiveConn, "inactiveConnection", rs.InactiveConn)
   181  				return false, nil
   182  			}
   183  			klog.V(5).InfoS("Deleting real server", "realServer", rsToDelete)
   184  			err := m.ipvs.DeleteRealServer(rsToDelete.VirtualServer, rs)
   185  			if err != nil {
   186  				return false, fmt.Errorf("delete destination %q err: %w", rs.String(), err)
   187  			}
   188  			return true, nil
   189  		}
   190  	}
   191  	return true, fmt.Errorf("failed to delete rs %q, can't find the real server", rsToDelete.String())
   192  }
   193  
   194  func (m *GracefulTerminationManager) tryDeleteRs() {
   195  	if !m.rsList.flushList(m.deleteRsFunc) {
   196  		klog.ErrorS(nil, "Try flush graceful termination list error")
   197  	}
   198  }
   199  
   200  // MoveRSOutofGracefulDeleteList to delete an rs and remove it from the rsList immediately
   201  func (m *GracefulTerminationManager) MoveRSOutofGracefulDeleteList(uniqueRS string) error {
   202  	rsToDelete, find := m.rsList.exist(uniqueRS)
   203  	if !find || rsToDelete == nil {
   204  		return fmt.Errorf("failed to find rs: %q", uniqueRS)
   205  	}
   206  	err := m.ipvs.DeleteRealServer(rsToDelete.VirtualServer, rsToDelete.RealServer)
   207  	if err != nil {
   208  		return err
   209  	}
   210  	m.rsList.remove(rsToDelete)
   211  	return nil
   212  }
   213  
   214  // Run start a goroutine to try to delete rs in the graceful delete rsList with an interval 1 minute
   215  func (m *GracefulTerminationManager) Run() {
   216  	go wait.Until(m.tryDeleteRs, rsCheckDeleteInterval, wait.NeverStop)
   217  }