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  }