actual_state_of_world.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /*
  2. Copyright 2019 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. /*
  14. Package cache implements data structures used by the kubelet plugin manager to
  15. keep track of registered plugins.
  16. */
  17. package cache
  18. import (
  19. "fmt"
  20. "sync"
  21. "time"
  22. "k8s.io/klog"
  23. )
  24. // ActualStateOfWorld defines a set of thread-safe operations for the kubelet
  25. // plugin manager's actual state of the world cache.
  26. // This cache contains a map of socket file path to plugin information of
  27. // all plugins attached to this node.
  28. type ActualStateOfWorld interface {
  29. // GetRegisteredPlugins generates and returns a list of plugins
  30. // that are successfully registered plugins in the current actual state of world.
  31. GetRegisteredPlugins() []PluginInfo
  32. // AddPlugin add the given plugin in the cache.
  33. // An error will be returned if socketPath of the PluginInfo object is empty.
  34. // Note that this is different from desired world cache's AddOrUpdatePlugin
  35. // because for the actual state of world cache, there won't be a scenario where
  36. // we need to update an existing plugin if the timestamps don't match. This is
  37. // because the plugin should have been unregistered in the reconciller and therefore
  38. // removed from the actual state of world cache first before adding it back into
  39. // the actual state of world cache again with the new timestamp
  40. AddPlugin(pluginInfo PluginInfo) error
  41. // RemovePlugin deletes the plugin with the given socket path from the actual
  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. // PluginExists checks if the given plugin exists in the current actual
  46. // state of world cache with the correct timestamp
  47. PluginExistsWithCorrectTimestamp(pluginInfo PluginInfo) bool
  48. }
  49. // NewActualStateOfWorld returns a new instance of ActualStateOfWorld
  50. func NewActualStateOfWorld() ActualStateOfWorld {
  51. return &actualStateOfWorld{
  52. socketFileToInfo: make(map[string]PluginInfo),
  53. }
  54. }
  55. type actualStateOfWorld struct {
  56. // socketFileToInfo is a map containing the set of successfully registered plugins
  57. // The keys are plugin socket file paths. The values are PluginInfo objects
  58. socketFileToInfo map[string]PluginInfo
  59. sync.RWMutex
  60. }
  61. var _ ActualStateOfWorld = &actualStateOfWorld{}
  62. // PluginInfo holds information of a plugin
  63. type PluginInfo struct {
  64. SocketPath string
  65. Timestamp time.Time
  66. }
  67. func (asw *actualStateOfWorld) AddPlugin(pluginInfo PluginInfo) error {
  68. asw.Lock()
  69. defer asw.Unlock()
  70. if pluginInfo.SocketPath == "" {
  71. return fmt.Errorf("socket path is empty")
  72. }
  73. if _, ok := asw.socketFileToInfo[pluginInfo.SocketPath]; ok {
  74. klog.V(2).Infof("Plugin (Path %s) exists in actual state cache", pluginInfo.SocketPath)
  75. }
  76. asw.socketFileToInfo[pluginInfo.SocketPath] = pluginInfo
  77. return nil
  78. }
  79. func (asw *actualStateOfWorld) RemovePlugin(socketPath string) {
  80. asw.Lock()
  81. defer asw.Unlock()
  82. delete(asw.socketFileToInfo, socketPath)
  83. }
  84. func (asw *actualStateOfWorld) GetRegisteredPlugins() []PluginInfo {
  85. asw.RLock()
  86. defer asw.RUnlock()
  87. currentPlugins := []PluginInfo{}
  88. for _, pluginInfo := range asw.socketFileToInfo {
  89. currentPlugins = append(currentPlugins, pluginInfo)
  90. }
  91. return currentPlugins
  92. }
  93. func (asw *actualStateOfWorld) PluginExistsWithCorrectTimestamp(pluginInfo PluginInfo) bool {
  94. asw.RLock()
  95. defer asw.RUnlock()
  96. // We need to check both if the socket file path exists, and the timestamp
  97. // matches the given plugin (from the desired state cache) timestamp
  98. actualStatePlugin, exists := asw.socketFileToInfo[pluginInfo.SocketPath]
  99. return exists && (actualStatePlugin.Timestamp == pluginInfo.Timestamp)
  100. }