github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/cloud/pkg/cloudhub/channelq/channelq.go (about) 1 package channelq 2 3 import ( 4 "fmt" 5 "strings" 6 "sync" 7 8 "k8s.io/apimachinery/pkg/api/meta" 9 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 "k8s.io/client-go/tools/cache" 11 "k8s.io/client-go/util/workqueue" 12 "k8s.io/klog" 13 14 beehiveContext "github.com/kubeedge/beehive/pkg/core/context" 15 beehiveModel "github.com/kubeedge/beehive/pkg/core/model" 16 "github.com/kubeedge/kubeedge/cloud/pkg/cloudhub/common/model" 17 hubconfig "github.com/kubeedge/kubeedge/cloud/pkg/cloudhub/config" 18 edgeconst "github.com/kubeedge/kubeedge/cloud/pkg/edgecontroller/constants" 19 edgemessagelayer "github.com/kubeedge/kubeedge/cloud/pkg/edgecontroller/messagelayer" 20 "github.com/kubeedge/kubeedge/cloud/pkg/synccontroller" 21 commonconst "github.com/kubeedge/kubeedge/common/constants" 22 ) 23 24 // ChannelMessageQueue is the channel implementation of MessageQueue 25 type ChannelMessageQueue struct { 26 queuePool sync.Map 27 storePool sync.Map 28 29 listQueuePool sync.Map 30 listStorePool sync.Map 31 32 ObjectSyncController *hubconfig.ObjectSyncController 33 } 34 35 // NewChannelMessageQueue initializes a new ChannelMessageQueue 36 func NewChannelMessageQueue(objectSyncController *hubconfig.ObjectSyncController) *ChannelMessageQueue { 37 return &ChannelMessageQueue{ 38 ObjectSyncController: objectSyncController, 39 } 40 } 41 42 // DispatchMessage gets the message from the cloud, extracts the 43 // node id from it, gets the message associated with the node 44 // and pushes the message to the queue 45 func (q *ChannelMessageQueue) DispatchMessage() { 46 for { 47 select { 48 case <-beehiveContext.Done(): 49 klog.Warning("Cloudhub channel eventqueue dispatch message loop stoped") 50 return 51 default: 52 } 53 msg, err := beehiveContext.Receive(model.SrcCloudHub) 54 if err != nil { 55 klog.Info("receive not Message format message") 56 continue 57 } 58 nodeID, err := GetNodeID(&msg) 59 if nodeID == "" || err != nil { 60 klog.Warning("node id is not found in the message") 61 continue 62 } 63 64 if isListResource(&msg) { 65 q.addListMessageToQueue(nodeID, &msg) 66 } else { 67 q.addMessageToQueue(nodeID, &msg) 68 } 69 } 70 } 71 72 func (q *ChannelMessageQueue) addListMessageToQueue(nodeID string, msg *beehiveModel.Message) { 73 nodeListQueue, err := q.GetNodeListQueue(nodeID) 74 if err != nil { 75 klog.Errorf("fail to get nodeListQueue for Node: %s", nodeID) 76 return 77 } 78 79 nodeListStore, err := q.GetNodeListStore(nodeID) 80 if err != nil { 81 klog.Errorf("fail to get nodeListStore for Node: %s", nodeID) 82 return 83 } 84 85 messageKey, _ := getListMsgKey(msg) 86 87 nodeListStore.Add(msg) 88 nodeListQueue.Add(messageKey) 89 } 90 91 func (q *ChannelMessageQueue) addMessageToQueue(nodeID string, msg *beehiveModel.Message) { 92 if msg.GetResourceVersion() == "" && !isDeleteMessage(msg) { 93 return 94 } 95 96 nodeQueue, err := q.GetNodeQueue(nodeID) 97 if err != nil { 98 klog.Errorf("fail to get nodeQueue for Node: %s", nodeID) 99 return 100 } 101 102 nodeStore, err := q.GetNodeStore(nodeID) 103 if err != nil { 104 klog.Errorf("fail to get nodeStore for Node: %s", nodeID) 105 return 106 } 107 108 messageKey, err := getMsgKey(msg) 109 if err != nil { 110 klog.Errorf("fail to get message key for message: %s", msg.Header.ID) 111 return 112 } 113 114 item, exist, _ := nodeStore.GetByKey(messageKey) 115 116 if !isDeleteMessage(msg) { 117 // If the message doesn't exist in the store, then compare it with 118 // the version stored in the database 119 if !exist { 120 resourceNamespace, _ := edgemessagelayer.GetNamespace(*msg) 121 resourceUID, err := GetMessageUID(*msg) 122 if err != nil { 123 klog.Errorf("fail to get message UID for message: %s", msg.Header.ID) 124 return 125 } 126 127 objectSync, err := q.ObjectSyncController.ObjectSyncLister.ObjectSyncs(resourceNamespace).Get(synccontroller.BuildObjectSyncName(nodeID, resourceUID)) 128 if err == nil && msg.GetResourceVersion() <= objectSync.ResourceVersion { 129 return 130 } 131 } 132 133 // Check if message is older than already in store, if it is, discard it directly 134 if exist { 135 msgInStore := item.(*beehiveModel.Message) 136 if msg.GetResourceVersion() <= msgInStore.GetResourceVersion() || 137 isDeleteMessage(msgInStore) { 138 return 139 } 140 } 141 } 142 143 nodeStore.Add(msg) 144 nodeQueue.Add(messageKey) 145 } 146 147 func getMsgKey(obj interface{}) (string, error) { 148 msg := obj.(*beehiveModel.Message) 149 150 if msg.GetGroup() == edgeconst.GroupResource { 151 resourceType, _ := edgemessagelayer.GetResourceType(*msg) 152 resourceNamespace, _ := edgemessagelayer.GetNamespace(*msg) 153 resourceName, _ := edgemessagelayer.GetResourceName(*msg) 154 return strings.Join([]string{resourceType, resourceNamespace, resourceName}, "/"), nil 155 } 156 157 return "", fmt.Errorf("Failed to get message key") 158 } 159 160 func getListMsgKey(obj interface{}) (string, error) { 161 msg := obj.(*beehiveModel.Message) 162 163 return msg.Header.ID, nil 164 } 165 166 func isListResource(msg *beehiveModel.Message) bool { 167 msgResource := msg.GetResource() 168 if strings.Contains(msgResource, beehiveModel.ResourceTypePodlist) || 169 strings.Contains(msgResource, commonconst.ResourceTypeServiceList) || 170 strings.Contains(msgResource, commonconst.ResourceTypeEndpointsList) || 171 strings.Contains(msgResource, "membership") || 172 strings.Contains(msgResource, "twin/cloud_updated") { 173 return true 174 } 175 176 if msg.GetOperation() == beehiveModel.ResponseOperation { 177 content, ok := msg.Content.(string) 178 if ok && content == "OK" { 179 return true 180 } 181 } 182 183 if msg.GetSource() == edgeconst.EdgeControllerModuleName { 184 resourceType, _ := edgemessagelayer.GetResourceType(*msg) 185 if resourceType == beehiveModel.ResourceTypeNode { 186 return true 187 } 188 } 189 190 return false 191 } 192 193 func isDeleteMessage(msg *beehiveModel.Message) bool { 194 if msg.GetOperation() == beehiveModel.DeleteOperation { 195 return true 196 } 197 deletionTimestamp, err := GetMessageDeletionTimestamp(msg) 198 if err != nil { 199 klog.Errorf("fail to get message DeletionTimestamp for message: %s", msg.Header.ID) 200 return false 201 } else if deletionTimestamp != nil { 202 return true 203 } 204 205 return false 206 } 207 208 // GetNodeID from "beehive/pkg/core/model".Message.Router.Resource 209 func GetNodeID(msg *beehiveModel.Message) (string, error) { 210 resource := msg.Router.Resource 211 tokens := strings.Split(resource, commonconst.ResourceSep) 212 numOfTokens := len(tokens) 213 for i, token := range tokens { 214 if token == model.ResNode && i+1 < numOfTokens && tokens[i+1] != "" { 215 return tokens[i+1], nil 216 } 217 } 218 219 return "", fmt.Errorf("No nodeID in Message.Router.Resource: %s", resource) 220 } 221 222 // Connect allocates the queues and stores for given node 223 func (q *ChannelMessageQueue) Connect(info *model.HubInfo) { 224 _, queueExist := q.queuePool.Load(info.NodeID) 225 _, storeExit := q.storePool.Load(info.NodeID) 226 227 _, listQueueExist := q.listQueuePool.Load(info.NodeID) 228 _, listStoreExit := q.listStorePool.Load(info.NodeID) 229 230 if queueExist && storeExit && listQueueExist && listStoreExit { 231 klog.Infof("edge node %s is already connected", info.NodeID) 232 return 233 } 234 235 if !queueExist { 236 nodeQueue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), info.NodeID) 237 q.queuePool.Store(info.NodeID, nodeQueue) 238 } 239 if !storeExit { 240 nodeStore := cache.NewStore(getMsgKey) 241 q.storePool.Store(info.NodeID, nodeStore) 242 } 243 if !listQueueExist { 244 nodeListQueue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), info.NodeID) 245 q.listQueuePool.Store(info.NodeID, nodeListQueue) 246 } 247 if !listStoreExit { 248 nodeListStore := cache.NewStore(getListMsgKey) 249 q.listStorePool.Store(info.NodeID, nodeListStore) 250 } 251 } 252 253 // Close closes queues and stores for given node 254 func (q *ChannelMessageQueue) Close(info *model.HubInfo) { 255 _, queueExist := q.queuePool.Load(info.NodeID) 256 _, storeExist := q.storePool.Load(info.NodeID) 257 258 _, listQueueExist := q.listQueuePool.Load(info.NodeID) 259 _, listStoreExit := q.listStorePool.Load(info.NodeID) 260 261 if !queueExist && !storeExist && !listQueueExist && !listStoreExit { 262 klog.Warningf("rChannel for edge node %s is already removed", info.NodeID) 263 return 264 } 265 266 if queueExist { 267 q.queuePool.Delete(info.NodeID) 268 } 269 if storeExist { 270 q.storePool.Delete(info.NodeID) 271 } 272 if listQueueExist { 273 q.listQueuePool.Delete(info.NodeID) 274 } 275 if listStoreExit { 276 q.listStorePool.Delete(info.NodeID) 277 } 278 } 279 280 // Publish sends message via the rchannel to Controllers 281 func (q *ChannelMessageQueue) Publish(msg *beehiveModel.Message) error { 282 switch msg.Router.Source { 283 case model.ResTwin: 284 beehiveContext.SendToGroup(model.SrcDeviceController, *msg) 285 default: 286 beehiveContext.SendToGroup(model.SrcEdgeController, *msg) 287 } 288 return nil 289 } 290 291 // GetNodeQueue returns the queue for given node 292 func (q *ChannelMessageQueue) GetNodeQueue(nodeID string) (workqueue.RateLimitingInterface, error) { 293 queue, ok := q.queuePool.Load(nodeID) 294 if !ok { 295 klog.Warningf("nodeQueue for edge node %s not found and created now", nodeID) 296 nodeQueue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), nodeID) 297 q.queuePool.Store(nodeID, nodeQueue) 298 return nodeQueue, nil 299 } 300 301 nodeQueue := queue.(workqueue.RateLimitingInterface) 302 return nodeQueue, nil 303 } 304 305 // GetNodeListQueue returns the listQueue for given node 306 func (q *ChannelMessageQueue) GetNodeListQueue(nodeID string) (workqueue.RateLimitingInterface, error) { 307 queue, ok := q.listQueuePool.Load(nodeID) 308 if !ok { 309 klog.Warningf("nodeListQueue for edge node %s not found and created now", nodeID) 310 nodeListQueue := workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), nodeID) 311 q.listQueuePool.Store(nodeID, nodeListQueue) 312 return nodeListQueue, nil 313 } 314 315 nodeListQueue := queue.(workqueue.RateLimitingInterface) 316 return nodeListQueue, nil 317 } 318 319 // GetNodeStore returns the store for given node 320 func (q *ChannelMessageQueue) GetNodeStore(nodeID string) (cache.Store, error) { 321 store, ok := q.storePool.Load(nodeID) 322 if !ok { 323 klog.Warningf("nodeStore for edge node %s not found and created now", nodeID) 324 nodeStore := cache.NewStore(getMsgKey) 325 q.storePool.Store(nodeID, nodeStore) 326 return nodeStore, nil 327 } 328 329 nodeStore := store.(cache.Store) 330 return nodeStore, nil 331 } 332 333 // GetNodeListStore returns the listStore for given node 334 func (q *ChannelMessageQueue) GetNodeListStore(nodeID string) (cache.Store, error) { 335 store, ok := q.listStorePool.Load(nodeID) 336 if !ok { 337 klog.Warningf("nodeListStore for edge node %s not found and created now", nodeID) 338 nodeListStore := cache.NewStore(getListMsgKey) 339 q.listStorePool.Store(nodeID, nodeListStore) 340 return nodeListStore, nil 341 } 342 343 nodeListStore := store.(cache.Store) 344 return nodeListStore, nil 345 } 346 347 // GetMessageUID returns the UID of the object in message 348 func GetMessageUID(msg beehiveModel.Message) (string, error) { 349 accessor, err := meta.Accessor(msg.Content) 350 if err != nil { 351 return "", err 352 } 353 354 return string(accessor.GetUID()), nil 355 } 356 357 // GetMessageDeletionTimestamp returns the deletionTimestamp of the object in message 358 func GetMessageDeletionTimestamp(msg *beehiveModel.Message) (*metav1.Time, error) { 359 accessor, err := meta.Accessor(msg.Content) 360 if err != nil { 361 return nil, err 362 } 363 364 return accessor.GetDeletionTimestamp(), nil 365 }