...

Source file src/k8s.io/kubernetes/pkg/kubelet/pluginmanager/cache/actual_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  // ActualStateOfWorld defines a set of thread-safe operations for the kubelet
    32  // plugin manager's actual 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 ActualStateOfWorld interface {
    36  
    37  	// GetRegisteredPlugins generates and returns a list of plugins
    38  	// that are successfully registered plugins in the current actual state of world.
    39  	GetRegisteredPlugins() []PluginInfo
    40  
    41  	// AddPlugin add the given plugin in the cache.
    42  	// An error will be returned if socketPath of the PluginInfo object is empty.
    43  	// Note that this is different from desired world cache's AddOrUpdatePlugin
    44  	// because for the actual state of world cache, there won't be a scenario where
    45  	// we need to update an existing plugin if the timestamps don't match. This is
    46  	// because the plugin should have been unregistered in the reconciler and therefore
    47  	// removed from the actual state of world cache first before adding it back into
    48  	// the actual state of world cache again with the new timestamp
    49  	AddPlugin(pluginInfo PluginInfo) error
    50  
    51  	// RemovePlugin deletes the plugin with the given socket path from the actual
    52  	// state of world.
    53  	// If a plugin does not exist with the given socket path, this is a no-op.
    54  	RemovePlugin(socketPath string)
    55  
    56  	// PluginExists checks if the given plugin exists in the current actual
    57  	// state of world cache with the correct timestamp
    58  	PluginExistsWithCorrectTimestamp(pluginInfo PluginInfo) bool
    59  }
    60  
    61  // NewActualStateOfWorld returns a new instance of ActualStateOfWorld
    62  func NewActualStateOfWorld() ActualStateOfWorld {
    63  	return &actualStateOfWorld{
    64  		socketFileToInfo: make(map[string]PluginInfo),
    65  	}
    66  }
    67  
    68  type actualStateOfWorld struct {
    69  
    70  	// socketFileToInfo is a map containing the set of successfully registered plugins
    71  	// The keys are plugin socket file paths. The values are PluginInfo objects
    72  	socketFileToInfo map[string]PluginInfo
    73  	sync.RWMutex
    74  }
    75  
    76  var _ ActualStateOfWorld = &actualStateOfWorld{}
    77  
    78  // PluginInfo holds information of a plugin
    79  type PluginInfo struct {
    80  	SocketPath string
    81  	Timestamp  time.Time
    82  	Handler    PluginHandler
    83  	Name       string
    84  }
    85  
    86  func (asw *actualStateOfWorld) AddPlugin(pluginInfo PluginInfo) error {
    87  	asw.Lock()
    88  	defer asw.Unlock()
    89  
    90  	if pluginInfo.SocketPath == "" {
    91  		return fmt.Errorf("socket path is empty")
    92  	}
    93  	if _, ok := asw.socketFileToInfo[pluginInfo.SocketPath]; ok {
    94  		klog.V(2).InfoS("Plugin exists in actual state cache", "path", pluginInfo.SocketPath)
    95  	}
    96  	asw.socketFileToInfo[pluginInfo.SocketPath] = pluginInfo
    97  	return nil
    98  }
    99  
   100  func (asw *actualStateOfWorld) RemovePlugin(socketPath string) {
   101  	asw.Lock()
   102  	defer asw.Unlock()
   103  
   104  	delete(asw.socketFileToInfo, socketPath)
   105  }
   106  
   107  func (asw *actualStateOfWorld) GetRegisteredPlugins() []PluginInfo {
   108  	asw.RLock()
   109  	defer asw.RUnlock()
   110  
   111  	currentPlugins := []PluginInfo{}
   112  	for _, pluginInfo := range asw.socketFileToInfo {
   113  		currentPlugins = append(currentPlugins, pluginInfo)
   114  	}
   115  	return currentPlugins
   116  }
   117  
   118  func (asw *actualStateOfWorld) PluginExistsWithCorrectTimestamp(pluginInfo PluginInfo) bool {
   119  	asw.RLock()
   120  	defer asw.RUnlock()
   121  
   122  	// We need to check both if the socket file path exists, and the timestamp
   123  	// matches the given plugin (from the desired state cache) timestamp
   124  	actualStatePlugin, exists := asw.socketFileToInfo[pluginInfo.SocketPath]
   125  	return exists && (actualStatePlugin.Timestamp == pluginInfo.Timestamp)
   126  }
   127  

View as plain text