desired_state_of_world.go 6.2 KB

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