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 }