...

Source file src/k8s.io/kubernetes/pkg/kubelet/pluginmanager/cache/desired_state_of_world.go

Documentation: k8s.io/kubernetes/pkg/kubelet/pluginmanager/cache

     1  /*
     2  Copyright 2019 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  /*
    18  Package cache implements data structures used by the kubelet plugin manager to
    19  keep track of registered plugins.
    20  */
    21  package cache
    22  
    23  import (
    24  	"fmt"
    25  	"sync"
    26  	"time"
    27  
    28  	"k8s.io/klog/v2"
    29  )
    30  
    31  // DesiredStateOfWorld defines a set of thread-safe operations for the kubelet
    32  // plugin manager's desired state of the world cache.
    33  // This cache contains a map of socket file path to plugin information of
    34  // all plugins attached to this node.
    35  type DesiredStateOfWorld interface {
    36  	// AddOrUpdatePlugin add the given plugin in the cache if it doesn't already exist.
    37  	// If it does exist in the cache, then the timestamp of the PluginInfo object in the cache will be updated.
    38  	// An error will be returned if socketPath is empty.
    39  	AddOrUpdatePlugin(socketPath string) error
    40  
    41  	// RemovePlugin deletes the plugin with the given socket path from the desired
    42  	// state of world.
    43  	// If a plugin does not exist with the given socket path, this is a no-op.
    44  	RemovePlugin(socketPath string)
    45  
    46  	// GetPluginsToRegister generates and returns a list of plugins
    47  	// in the current desired state of world.
    48  	GetPluginsToRegister() []PluginInfo
    49  
    50  	// PluginExists checks if the given socket path exists in the current desired
    51  	// state of world cache
    52  	PluginExists(socketPath string) bool
    53  }
    54  
    55  // NewDesiredStateOfWorld returns a new instance of DesiredStateOfWorld.
    56  func NewDesiredStateOfWorld() DesiredStateOfWorld {
    57  	return &desiredStateOfWorld{
    58  		socketFileToInfo: make(map[string]PluginInfo),
    59  	}
    60  }
    61  
    62  type desiredStateOfWorld struct {
    63  
    64  	// socketFileToInfo is a map containing the set of successfully registered plugins
    65  	// The keys are plugin socket file paths. The values are PluginInfo objects
    66  	socketFileToInfo map[string]PluginInfo
    67  	sync.RWMutex
    68  }
    69  
    70  var _ DesiredStateOfWorld = &desiredStateOfWorld{}
    71  
    72  // Generate a detailed error msg for logs
    73  func generatePluginMsgDetailed(prefixMsg, suffixMsg, socketPath, details string) (detailedMsg string) {
    74  	return fmt.Sprintf("%v for plugin at %q %v %v", prefixMsg, socketPath, details, suffixMsg)
    75  }
    76  
    77  // Generate a simplified error msg for events and a detailed error msg for logs
    78  func generatePluginMsg(prefixMsg, suffixMsg, socketPath, details string) (simpleMsg, detailedMsg string) {
    79  	simpleMsg = fmt.Sprintf("%v for plugin at %q %v", prefixMsg, socketPath, suffixMsg)
    80  	return simpleMsg, generatePluginMsgDetailed(prefixMsg, suffixMsg, socketPath, details)
    81  }
    82  
    83  // GenerateMsgDetailed returns detailed msgs for plugins to register
    84  // that can be used in logs.
    85  // The msg format follows the pattern "<prefixMsg> <plugin details> <suffixMsg>"
    86  func (plugin *PluginInfo) GenerateMsgDetailed(prefixMsg, suffixMsg string) (detailedMsg string) {
    87  	detailedStr := fmt.Sprintf("(plugin details: %v)", plugin)
    88  	return generatePluginMsgDetailed(prefixMsg, suffixMsg, plugin.SocketPath, detailedStr)
    89  }
    90  
    91  // GenerateMsg returns simple and detailed msgs for plugins to register
    92  // that is user friendly and a detailed msg that can be used in logs.
    93  // The msg format follows the pattern "<prefixMsg> <plugin details> <suffixMsg>".
    94  func (plugin *PluginInfo) GenerateMsg(prefixMsg, suffixMsg string) (simpleMsg, detailedMsg string) {
    95  	detailedStr := fmt.Sprintf("(plugin details: %v)", plugin)
    96  	return generatePluginMsg(prefixMsg, suffixMsg, plugin.SocketPath, detailedStr)
    97  }
    98  
    99  // GenerateErrorDetailed returns detailed errors for plugins to register
   100  // that can be used in logs.
   101  // The msg format follows the pattern "<prefixMsg> <plugin details>: <err> ",
   102  func (plugin *PluginInfo) GenerateErrorDetailed(prefixMsg string, err error) (detailedErr error) {
   103  	return fmt.Errorf(plugin.GenerateMsgDetailed(prefixMsg, errSuffix(err)))
   104  }
   105  
   106  // GenerateError returns simple and detailed errors for plugins to register
   107  // that is user friendly and a detailed error that can be used in logs.
   108  // The msg format follows the pattern "<prefixMsg> <plugin details>: <err> ".
   109  func (plugin *PluginInfo) GenerateError(prefixMsg string, err error) (simpleErr, detailedErr error) {
   110  	simpleMsg, detailedMsg := plugin.GenerateMsg(prefixMsg, errSuffix(err))
   111  	return fmt.Errorf(simpleMsg), fmt.Errorf(detailedMsg)
   112  }
   113  
   114  // Generates an error string with the format ": <err>" if err exists
   115  func errSuffix(err error) string {
   116  	errStr := ""
   117  	if err != nil {
   118  		errStr = fmt.Sprintf(": %v", err)
   119  	}
   120  	return errStr
   121  }
   122  
   123  func (dsw *desiredStateOfWorld) AddOrUpdatePlugin(socketPath string) error {
   124  	dsw.Lock()
   125  	defer dsw.Unlock()
   126  
   127  	if socketPath == "" {
   128  		return fmt.Errorf("socket path is empty")
   129  	}
   130  	if _, ok := dsw.socketFileToInfo[socketPath]; ok {
   131  		klog.V(2).InfoS("Plugin exists in desired state cache, timestamp will be updated", "path", socketPath)
   132  	}
   133  
   134  	// Update the PluginInfo object.
   135  	// Note that we only update the timestamp in the desired state of world, not the actual state of world
   136  	// because in the reconciler, we need to check if the plugin in the actual state of world is the same
   137  	// version as the plugin in the desired state of world
   138  	dsw.socketFileToInfo[socketPath] = PluginInfo{
   139  		SocketPath: socketPath,
   140  		Timestamp:  time.Now(),
   141  	}
   142  	return nil
   143  }
   144  
   145  func (dsw *desiredStateOfWorld) RemovePlugin(socketPath string) {
   146  	dsw.Lock()
   147  	defer dsw.Unlock()
   148  
   149  	delete(dsw.socketFileToInfo, socketPath)
   150  }
   151  
   152  func (dsw *desiredStateOfWorld) GetPluginsToRegister() []PluginInfo {
   153  	dsw.RLock()
   154  	defer dsw.RUnlock()
   155  
   156  	pluginsToRegister := []PluginInfo{}
   157  	for _, pluginInfo := range dsw.socketFileToInfo {
   158  		pluginsToRegister = append(pluginsToRegister, pluginInfo)
   159  	}
   160  	return pluginsToRegister
   161  }
   162  
   163  func (dsw *desiredStateOfWorld) PluginExists(socketPath string) bool {
   164  	dsw.RLock()
   165  	defer dsw.RUnlock()
   166  
   167  	_, exists := dsw.socketFileToInfo[socketPath]
   168  	return exists
   169  }
   170  

View as plain text