github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edge/pkg/devicetwin/dtmanager/membership.go (about)

     1  package dtmanager
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  	"sync"
     8  	"time"
     9  
    10  	"k8s.io/klog"
    11  
    12  	"github.com/kubeedge/beehive/pkg/core/model"
    13  	"github.com/kubeedge/kubeedge/edge/pkg/common/modules"
    14  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtclient"
    15  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtcommon"
    16  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtcontext"
    17  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dttype"
    18  )
    19  
    20  var (
    21  	//memActionCallBack map for action to callback
    22  	memActionCallBack map[string]CallBack
    23  	mutex             sync.Mutex
    24  )
    25  
    26  //MemWorker deal membership event
    27  type MemWorker struct {
    28  	Worker
    29  	Group string
    30  }
    31  
    32  //Start worker
    33  func (mw MemWorker) Start() {
    34  	initMemActionCallBack()
    35  	for {
    36  		select {
    37  		case msg, ok := <-mw.ReceiverChan:
    38  			if !ok {
    39  				return
    40  			}
    41  			if dtMsg, isDTMessage := msg.(*dttype.DTMessage); isDTMessage {
    42  				if fn, exist := memActionCallBack[dtMsg.Action]; exist {
    43  					_, err := fn(mw.DTContexts, dtMsg.Identity, dtMsg.Msg)
    44  					if err != nil {
    45  						klog.Errorf("MemModule deal %s event failed: %v", dtMsg.Action, err)
    46  					}
    47  				} else {
    48  					klog.Errorf("MemModule deal %s event failed, not found callback", dtMsg.Action)
    49  				}
    50  			}
    51  
    52  		case v, ok := <-mw.HeartBeatChan:
    53  			if !ok {
    54  				return
    55  			}
    56  			if err := mw.DTContexts.HeartBeat(mw.Group, v); err != nil {
    57  				return
    58  			}
    59  		}
    60  	}
    61  }
    62  
    63  func initMemActionCallBack() {
    64  	memActionCallBack = make(map[string]CallBack)
    65  	memActionCallBack[dtcommon.MemGet] = dealMerbershipGet
    66  	memActionCallBack[dtcommon.MemUpdated] = dealMembershipUpdated
    67  	memActionCallBack[dtcommon.MemDetailResult] = dealMembershipDetail
    68  }
    69  func getRemoveList(context *dtcontext.DTContext, devices []dttype.Device) []dttype.Device {
    70  	var toRemove []dttype.Device
    71  	context.DeviceList.Range(func(key interface{}, value interface{}) bool {
    72  		isExist := false
    73  		for _, v := range devices {
    74  			if strings.Compare(v.ID, key.(string)) == 0 {
    75  				isExist = true
    76  			}
    77  		}
    78  		if !isExist {
    79  			toRemove = append(toRemove, dttype.Device{ID: key.(string)})
    80  		}
    81  		return true
    82  	})
    83  	return toRemove
    84  }
    85  func dealMembershipDetail(context *dtcontext.DTContext, resource string, msg interface{}) (interface{}, error) {
    86  	klog.Info("Deal node detail info")
    87  	message, ok := msg.(*model.Message)
    88  	if !ok {
    89  		return nil, errors.New("msg not Message type")
    90  	}
    91  
    92  	contentData, ok := message.Content.([]byte)
    93  	if !ok {
    94  		return nil, errors.New("assertion failed")
    95  	}
    96  
    97  	devices, err := dttype.UnmarshalMembershipDetail(contentData)
    98  	if err != nil {
    99  		klog.Errorf("Unmarshal membership info failed , err: %#v", err)
   100  		return nil, err
   101  	}
   102  
   103  	baseMessage := dttype.BaseMessage{EventID: devices.EventID}
   104  	defer context.UnlockAll()
   105  	context.LockAll()
   106  	var toRemove []dttype.Device
   107  	isDelta := false
   108  	Added(context, devices.Devices, baseMessage, isDelta)
   109  	toRemove = getRemoveList(context, devices.Devices)
   110  
   111  	if toRemove != nil || len(toRemove) != 0 {
   112  		Removed(context, toRemove, baseMessage, isDelta)
   113  	}
   114  	klog.Info("Deal node detail info successful")
   115  	return nil, nil
   116  }
   117  
   118  func dealMembershipUpdated(context *dtcontext.DTContext, resource string, msg interface{}) (interface{}, error) {
   119  	klog.Infof("Membership event")
   120  	message, ok := msg.(*model.Message)
   121  	if !ok {
   122  		return nil, errors.New("msg not Message type")
   123  	}
   124  
   125  	contentData, ok := message.Content.([]byte)
   126  	if !ok {
   127  		return nil, errors.New("assertion failed")
   128  	}
   129  
   130  	updateEdgeGroups, err := dttype.UnmarshalMembershipUpdate(contentData)
   131  	if err != nil {
   132  		klog.Errorf("Unmarshal membership info failed , err: %#v", err)
   133  		return nil, err
   134  	}
   135  
   136  	baseMessage := dttype.BaseMessage{EventID: updateEdgeGroups.EventID}
   137  	if updateEdgeGroups.AddDevices != nil && len(updateEdgeGroups.AddDevices) > 0 {
   138  		//add device
   139  		Added(context, updateEdgeGroups.AddDevices, baseMessage, false)
   140  	}
   141  	if updateEdgeGroups.RemoveDevices != nil && len(updateEdgeGroups.RemoveDevices) > 0 {
   142  		// delete device
   143  		Removed(context, updateEdgeGroups.RemoveDevices, baseMessage, false)
   144  	}
   145  	return nil, nil
   146  }
   147  
   148  func dealMerbershipGet(context *dtcontext.DTContext, resource string, msg interface{}) (interface{}, error) {
   149  	klog.Infof("MEMBERSHIP EVENT")
   150  	message, ok := msg.(*model.Message)
   151  	if !ok {
   152  		return nil, errors.New("msg not Message type")
   153  	}
   154  
   155  	contentData, ok := message.Content.([]byte)
   156  	if !ok {
   157  		return nil, errors.New("assertion failed")
   158  	}
   159  
   160  	DealGetMembership(context, contentData)
   161  	return nil, nil
   162  }
   163  
   164  // Added add device to the edge group
   165  func Added(context *dtcontext.DTContext, toAdd []dttype.Device, baseMessage dttype.BaseMessage, delta bool) {
   166  	klog.Infof("Add devices to edge group")
   167  	if !delta {
   168  		baseMessage.EventID = ""
   169  	}
   170  	if toAdd == nil || len(toAdd) == 0 {
   171  		return
   172  	}
   173  	dealType := 0
   174  	if !delta {
   175  		dealType = 1
   176  	}
   177  	for _, device := range toAdd {
   178  		//if device has existed, step out
   179  		deviceModel, deviceExist := context.GetDevice(device.ID)
   180  		if deviceExist {
   181  			if delta {
   182  				klog.Errorf("Add device %s failed, has existed", device.ID)
   183  				continue
   184  			}
   185  			DeviceUpdated(context, device.ID, device.Attributes, baseMessage, dealType)
   186  			DealDeviceTwin(context, device.ID, baseMessage.EventID, device.Twin, dealType)
   187  			//todo sync twin
   188  			continue
   189  		}
   190  
   191  		var deviceMutex sync.Mutex
   192  		context.DeviceMutex.Store(device.ID, &deviceMutex)
   193  
   194  		if delta {
   195  			context.Lock(device.ID)
   196  		}
   197  
   198  		deviceModel = &dttype.Device{ID: device.ID, Name: device.Name, Description: device.Description, State: device.State}
   199  		context.DeviceList.Store(device.ID, deviceModel)
   200  
   201  		//write to sqlite
   202  		var err error
   203  		adds := make([]dtclient.Device, 0)
   204  		addAttr := make([]dtclient.DeviceAttr, 0)
   205  		addTwin := make([]dtclient.DeviceTwin, 0)
   206  		adds = append(adds, dtclient.Device{
   207  			ID:          device.ID,
   208  			Name:        device.Name,
   209  			Description: device.Description,
   210  			State:       device.State})
   211  		for i := 1; i <= dtcommon.RetryTimes; i++ {
   212  			err = dtclient.AddDeviceTrans(adds, addAttr, addTwin)
   213  			if err == nil {
   214  				break
   215  			}
   216  			time.Sleep(dtcommon.RetryInterval)
   217  		}
   218  
   219  		if err != nil {
   220  			klog.Errorf("Add device %s failed due to some error ,err: %#v", device.ID, err)
   221  			context.DeviceList.Delete(device.ID)
   222  			context.Unlock(device.ID)
   223  			continue
   224  			//todo
   225  		}
   226  		if device.Twin != nil {
   227  			klog.Infof("Add device twin during first adding device %s", device.ID)
   228  			DealDeviceTwin(context, device.ID, baseMessage.EventID, device.Twin, dealType)
   229  		}
   230  
   231  		if device.Attributes != nil {
   232  			klog.Infof("Add device attr during first adding device %s", device.ID)
   233  			DeviceUpdated(context, device.ID, device.Attributes, baseMessage, dealType)
   234  		}
   235  		topic := dtcommon.MemETPrefix + context.NodeName + dtcommon.MemETUpdateSuffix
   236  		baseMessage := dttype.BuildBaseMessage()
   237  		addedDevices := make([]dttype.Device, 0)
   238  		addedDevices = append(addedDevices, device)
   239  		addedResult := dttype.MembershipUpdate{BaseMessage: baseMessage, AddDevices: addedDevices}
   240  		result, err := dttype.MarshalMembershipUpdate(addedResult)
   241  		if err != nil {
   242  
   243  		} else {
   244  			context.Send("",
   245  				dtcommon.SendToEdge,
   246  				dtcommon.CommModule,
   247  				context.BuildModelMessage(modules.BusGroup, "", topic, "publish", result))
   248  		}
   249  		if delta {
   250  			context.Unlock(device.ID)
   251  		}
   252  	}
   253  }
   254  
   255  // Removed remove device from the edge group
   256  func Removed(context *dtcontext.DTContext, toRemove []dttype.Device, baseMessage dttype.BaseMessage, delta bool) {
   257  	klog.Infof("Begin to remove devices")
   258  	if !delta {
   259  		baseMessage.EventID = ""
   260  	}
   261  	for _, device := range toRemove {
   262  		//update sqlite
   263  		_, deviceExist := context.GetDevice(device.ID)
   264  		if !deviceExist {
   265  			klog.Errorf("Remove device %s failed, not existed", device.ID)
   266  			continue
   267  		}
   268  		if delta {
   269  			context.Lock(device.ID)
   270  		}
   271  		deletes := make([]string, 0)
   272  		deletes = append(deletes, device.ID)
   273  		for i := 1; i <= dtcommon.RetryTimes; i++ {
   274  			err := dtclient.DeleteDeviceTrans(deletes)
   275  			if err != nil {
   276  				klog.Errorf("Delete document of device %s failed at %d time, err: %#v", device.ID, i, err)
   277  			} else {
   278  				klog.Infof("Delete document of device %s successful", device.ID)
   279  				break
   280  			}
   281  			time.Sleep(dtcommon.RetryInterval)
   282  		}
   283  		//todo
   284  		context.DeviceList.Delete(device.ID)
   285  		context.DeviceMutex.Delete(device.ID)
   286  		if delta {
   287  			context.Unlock(device.ID)
   288  		}
   289  		topic := dtcommon.MemETPrefix + context.NodeName + dtcommon.MemETUpdateSuffix
   290  		baseMessage := dttype.BuildBaseMessage()
   291  		removeDevices := make([]dttype.Device, 0)
   292  		removeDevices = append(removeDevices, device)
   293  		deleteResult := dttype.MembershipUpdate{BaseMessage: baseMessage, RemoveDevices: removeDevices}
   294  		result, err := dttype.MarshalMembershipUpdate(deleteResult)
   295  		if err != nil {
   296  
   297  		} else {
   298  			context.Send("",
   299  				dtcommon.SendToEdge,
   300  				dtcommon.CommModule,
   301  				context.BuildModelMessage(modules.BusGroup, "", topic, "publish", result))
   302  		}
   303  
   304  		klog.Infof("Remove device %s successful", device.ID)
   305  	}
   306  }
   307  
   308  // DealGetMembership deal get membership event
   309  func DealGetMembership(context *dtcontext.DTContext, payload []byte) error {
   310  	klog.Info("Deal getting membership event")
   311  	result := []byte("")
   312  	edgeGet, err := dttype.UnmarshalBaseMessage(payload)
   313  	para := dttype.Parameter{}
   314  	now := time.Now().UnixNano() / 1e6
   315  	if err != nil {
   316  		klog.Errorf("Unmarshal get membership info %s failed , err: %#v", string(payload), err)
   317  		para.Code = dtcommon.BadRequestCode
   318  		para.Reason = fmt.Sprintf("Unmarshal get membership info %s failed , err: %#v", string(payload), err)
   319  		var jsonErr error
   320  		result, jsonErr = dttype.BuildErrorResult(para)
   321  		if jsonErr != nil {
   322  			klog.Errorf("Unmarshal error result error, err: %v", jsonErr)
   323  		}
   324  	} else {
   325  		para.EventID = edgeGet.EventID
   326  		var devices []*dttype.Device
   327  		context.DeviceList.Range(func(key interface{}, value interface{}) bool {
   328  			deviceModel, ok := value.(*dttype.Device)
   329  			if !ok {
   330  
   331  			} else {
   332  				devices = append(devices, deviceModel)
   333  			}
   334  			return true
   335  		})
   336  
   337  		payload, err := dttype.BuildMembershipGetResult(dttype.BaseMessage{EventID: edgeGet.EventID, Timestamp: now}, devices)
   338  		if err != nil {
   339  			klog.Errorf("Marshal membership failed while deal get membership ,err: %#v", err)
   340  		} else {
   341  			result = payload
   342  		}
   343  
   344  	}
   345  	topic := dtcommon.MemETPrefix + context.NodeName + dtcommon.MemETGetResultSuffix
   346  	klog.Infof("Deal getting membership successful and send the result")
   347  
   348  	context.Send("",
   349  		dtcommon.SendToEdge,
   350  		dtcommon.CommModule,
   351  		context.BuildModelMessage(modules.BusGroup, "", topic, "publish", result))
   352  
   353  	return nil
   354  
   355  }
   356  
   357  //SyncDeviceFromSqlite sync device from sqlite
   358  func SyncDeviceFromSqlite(context *dtcontext.DTContext, deviceID string) error {
   359  	klog.Infof("Sync device detail info from DB of device %s", deviceID)
   360  	_, exist := context.GetDevice(deviceID)
   361  	if !exist {
   362  		var deviceMutex sync.Mutex
   363  		context.DeviceMutex.Store(deviceID, &deviceMutex)
   364  	}
   365  
   366  	devices, err := dtclient.QueryDevice("id", deviceID)
   367  	if err != nil {
   368  		klog.Errorf("query device attr failed: %v", err)
   369  		return err
   370  	}
   371  	if len(*devices) == 0 {
   372  		return errors.New("Not found device")
   373  	}
   374  	dbDoc := (*devices)[0]
   375  
   376  	deviceAttr, err := dtclient.QueryDeviceAttr("deviceid", deviceID)
   377  	if err != nil {
   378  		klog.Errorf("query device attr failed: %v", err)
   379  		return err
   380  	}
   381  
   382  	deviceTwin, err := dtclient.QueryDeviceTwin("deviceid", deviceID)
   383  	if err != nil {
   384  		klog.Errorf("query device twin failed: %v", err)
   385  		return err
   386  	}
   387  
   388  	context.DeviceList.Store(deviceID, &dttype.Device{
   389  		ID:          deviceID,
   390  		Name:        dbDoc.Name,
   391  		Description: dbDoc.Description,
   392  		State:       dbDoc.State,
   393  		LastOnline:  dbDoc.LastOnline,
   394  		Attributes:  dttype.DeviceAttrToMsgAttr(*deviceAttr),
   395  		Twin:        dttype.DeviceTwinToMsgTwin(*deviceTwin)})
   396  
   397  	return nil
   398  }