github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/cloud/pkg/devicecontroller/controller/downstream.go (about)

     1  /*
     2  Copyright 2019 The KubeEdge Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8     http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package controller
    18  
    19  import (
    20  	"encoding/json"
    21  	"reflect"
    22  	"strconv"
    23  	"time"
    24  
    25  	"github.com/satori/go.uuid"
    26  	"k8s.io/api/core/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/apimachinery/pkg/watch"
    29  	"k8s.io/client-go/kubernetes"
    30  	"k8s.io/client-go/rest"
    31  	"k8s.io/klog"
    32  
    33  	beehiveContext "github.com/kubeedge/beehive/pkg/core/context"
    34  	"github.com/kubeedge/beehive/pkg/core/model"
    35  	"github.com/kubeedge/kubeedge/cloud/pkg/apis/devices/v1alpha1"
    36  	"github.com/kubeedge/kubeedge/cloud/pkg/devicecontroller/constants"
    37  	"github.com/kubeedge/kubeedge/cloud/pkg/devicecontroller/manager"
    38  	"github.com/kubeedge/kubeedge/cloud/pkg/devicecontroller/messagelayer"
    39  	"github.com/kubeedge/kubeedge/cloud/pkg/devicecontroller/types"
    40  	"github.com/kubeedge/kubeedge/cloud/pkg/devicecontroller/utils"
    41  )
    42  
    43  // Constants for protocol, datatype, configmap, deviceProfile
    44  const (
    45  	OPCUA     = "opcua"
    46  	ModbusRTU = "modbus-rtu"
    47  	ModbusTCP = "modbus-tcp"
    48  	Modbus    = "modbus"
    49  	Bluetooth = "bluetooth"
    50  
    51  	DataTypeInt    = "int"
    52  	DataTypeString = "string"
    53  
    54  	ConfigMapKind    = "ConfigMap"
    55  	ConfigMapVersion = "v1"
    56  
    57  	DeviceProfileConfigPrefix = "device-profile-config-"
    58  
    59  	DeviceProfileJSON = "deviceProfile.json"
    60  )
    61  
    62  // DownstreamController watch kubernetes api server and send change to edge
    63  type DownstreamController struct {
    64  	kubeClient   *kubernetes.Clientset
    65  	messageLayer messagelayer.MessageLayer
    66  
    67  	deviceManager      *manager.DeviceManager
    68  	deviceModelManager *manager.DeviceModelManager
    69  	configMapManager   *manager.ConfigMapManager
    70  
    71  	crdClient *rest.RESTClient
    72  }
    73  
    74  // syncDeviceModel is used to get events from informer
    75  func (dc *DownstreamController) syncDeviceModel() {
    76  	for {
    77  		select {
    78  		case <-beehiveContext.Done():
    79  			klog.Info("stop syncDeviceModel")
    80  			return
    81  		case e := <-dc.deviceModelManager.Events():
    82  			deviceModel, ok := e.Object.(*v1alpha1.DeviceModel)
    83  			if !ok {
    84  				klog.Warningf("object type: %T unsupported", deviceModel)
    85  				continue
    86  			}
    87  			switch e.Type {
    88  			case watch.Added:
    89  				dc.deviceModelAdded(deviceModel)
    90  			case watch.Deleted:
    91  				dc.deviceModelDeleted(deviceModel)
    92  			case watch.Modified:
    93  				dc.deviceModelUpdated(deviceModel)
    94  			default:
    95  				klog.Warningf("deviceModel event type: %s unsupported", e.Type)
    96  			}
    97  		}
    98  	}
    99  }
   100  
   101  // deviceModelAdded is function to process addition of new deviceModel in apiserver
   102  func (dc *DownstreamController) deviceModelAdded(deviceModel *v1alpha1.DeviceModel) {
   103  	// nothing to do when deviceModel added, only add in map
   104  	dc.deviceModelManager.DeviceModel.Store(deviceModel.Name, deviceModel)
   105  }
   106  
   107  // isDeviceModelUpdated is function to check if deviceModel is actually updated
   108  func isDeviceModelUpdated(oldTwin *v1alpha1.DeviceModel, newTwin *v1alpha1.DeviceModel) bool {
   109  	// does not care fields
   110  	oldTwin.ObjectMeta.ResourceVersion = newTwin.ObjectMeta.ResourceVersion
   111  	oldTwin.ObjectMeta.Generation = newTwin.ObjectMeta.Generation
   112  
   113  	// return true if ObjectMeta or Spec or Status changed, else false
   114  	return !reflect.DeepEqual(oldTwin.ObjectMeta, newTwin.ObjectMeta) || !reflect.DeepEqual(oldTwin.Spec, newTwin.Spec)
   115  }
   116  
   117  // deviceModelUpdated is function to process updated deviceModel
   118  func (dc *DownstreamController) deviceModelUpdated(deviceModel *v1alpha1.DeviceModel) {
   119  	value, ok := dc.deviceModelManager.DeviceModel.Load(deviceModel.Name)
   120  	dc.deviceModelManager.DeviceModel.Store(deviceModel.Name, deviceModel)
   121  	if ok {
   122  		cachedDeviceModel := value.(*v1alpha1.DeviceModel)
   123  		if isDeviceModelUpdated(cachedDeviceModel, deviceModel) {
   124  			dc.updateAllConfigMaps(deviceModel)
   125  		}
   126  	} else {
   127  		dc.deviceModelAdded(deviceModel)
   128  	}
   129  }
   130  
   131  // updateAllConfigMaps is function to update configMaps which refer to an updated deviceModel
   132  func (dc *DownstreamController) updateAllConfigMaps(deviceModel *v1alpha1.DeviceModel) {
   133  	//TODO: add logic to update all config maps, How to manage if a property is deleted but a device is referring that property. Need to come up with a design.
   134  }
   135  
   136  // deviceModelDeleted is function to process deleted deviceModel
   137  func (dc *DownstreamController) deviceModelDeleted(deviceModel *v1alpha1.DeviceModel) {
   138  	// TODO: Need to use finalizer like method to delete all devices referring to this model. Need to come up with a design.
   139  	dc.deviceModelManager.DeviceModel.Delete(deviceModel.Name)
   140  }
   141  
   142  // syncDevice is used to get device events from informer
   143  func (dc *DownstreamController) syncDevice() {
   144  	for {
   145  		select {
   146  		case <-beehiveContext.Done():
   147  			klog.Info("Stop syncDevice")
   148  			return
   149  		case e := <-dc.deviceManager.Events():
   150  			device, ok := e.Object.(*v1alpha1.Device)
   151  			if !ok {
   152  				klog.Warningf("Object type: %T unsupported", device)
   153  				continue
   154  			}
   155  			switch e.Type {
   156  			case watch.Added:
   157  				dc.deviceAdded(device)
   158  			case watch.Deleted:
   159  				dc.deviceDeleted(device)
   160  			case watch.Modified:
   161  				dc.deviceUpdated(device)
   162  			default:
   163  				klog.Warningf("Device event type: %s unsupported", e.Type)
   164  			}
   165  		}
   166  	}
   167  }
   168  
   169  // addToConfigMap adds device in the configmap
   170  func (dc *DownstreamController) addToConfigMap(device *v1alpha1.Device) {
   171  	configMap, ok := dc.configMapManager.ConfigMap.Load(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values[0])
   172  	if !ok {
   173  		nodeConfigMap := &v1.ConfigMap{}
   174  		nodeConfigMap.Kind = ConfigMapKind
   175  		nodeConfigMap.APIVersion = ConfigMapVersion
   176  		nodeConfigMap.Name = DeviceProfileConfigPrefix + device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values[0]
   177  		nodeConfigMap.Namespace = device.Namespace
   178  		nodeConfigMap.Data = make(map[string]string)
   179  		// TODO: how to handle 2 device of multiple namespaces bind to same node ?
   180  		dc.addDeviceProfile(device, nodeConfigMap)
   181  		// store new config map
   182  		dc.configMapManager.ConfigMap.Store(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values[0], nodeConfigMap)
   183  
   184  		if _, err := dc.kubeClient.CoreV1().ConfigMaps(device.Namespace).Get(nodeConfigMap.Name, metav1.GetOptions{}); err != nil {
   185  			if _, err := dc.kubeClient.CoreV1().ConfigMaps(device.Namespace).Create(nodeConfigMap); err != nil {
   186  				klog.Errorf("Failed to create config map %v in namespace %v, error %v", nodeConfigMap, device.Namespace, err)
   187  				return
   188  			}
   189  		}
   190  		if _, err := dc.kubeClient.CoreV1().ConfigMaps(device.Namespace).Update(nodeConfigMap); err != nil {
   191  			klog.Errorf("Failed to update config map %v in namespace %v, error %v", nodeConfigMap, device.Namespace, err)
   192  			return
   193  		}
   194  		return
   195  	}
   196  	nodeConfigMap, ok := configMap.(*v1.ConfigMap)
   197  	if !ok {
   198  		klog.Error("Failed to assert to configmap")
   199  		return
   200  	}
   201  	dc.addDeviceProfile(device, nodeConfigMap)
   202  	// store new config map
   203  	dc.configMapManager.ConfigMap.Store(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values[0], nodeConfigMap)
   204  	if _, err := dc.kubeClient.CoreV1().ConfigMaps(device.Namespace).Update(nodeConfigMap); err != nil {
   205  		klog.Errorf("Failed to update config map %v in namespace %v", nodeConfigMap, device.Namespace)
   206  		return
   207  	}
   208  }
   209  
   210  // addDeviceProfile is function to add deviceProfile in configMap
   211  func (dc *DownstreamController) addDeviceProfile(device *v1alpha1.Device, configMap *v1.ConfigMap) {
   212  	deviceProfile := &types.DeviceProfile{}
   213  	dp, ok := configMap.Data[DeviceProfileJSON]
   214  	if !ok {
   215  		// create deviceProfileStruct
   216  		deviceProfile.DeviceInstances = make([]*types.DeviceInstance, 0)
   217  		deviceProfile.DeviceModels = make([]*types.DeviceModel, 0)
   218  		deviceProfile.PropertyVisitors = make([]*types.PropertyVisitor, 0)
   219  		deviceProfile.Protocols = make([]*types.Protocol, 0)
   220  	} else {
   221  		err := json.Unmarshal([]byte(dp), deviceProfile)
   222  		if err != nil {
   223  			klog.Errorf("Failed to Unmarshal deviceprofile: %v", deviceProfile)
   224  			return
   225  		}
   226  	}
   227  
   228  	addDeviceInstanceAndProtocol(device, deviceProfile)
   229  	dm, ok := dc.deviceModelManager.DeviceModel.Load(device.Spec.DeviceModelRef.Name)
   230  	if !ok {
   231  		klog.Errorf("Failed to get device model %v", device.Spec.DeviceModelRef.Name)
   232  		return
   233  	}
   234  	deviceModel := dm.(*v1alpha1.DeviceModel)
   235  	// if model already exists no need to add model and visitors
   236  	checkModelExists := false
   237  	for _, dm := range deviceProfile.DeviceModels {
   238  		if dm.Name == deviceModel.Name {
   239  			checkModelExists = true
   240  			break
   241  		}
   242  	}
   243  	if checkModelExists != true {
   244  		addDeviceModelAndVisitors(deviceModel, deviceProfile)
   245  	}
   246  	bytes, err := json.Marshal(deviceProfile)
   247  	if err != nil {
   248  		klog.Errorf("Failed to marshal deviceprofile: %v", deviceProfile)
   249  		return
   250  	}
   251  	configMap.Data[DeviceProfileJSON] = string(bytes)
   252  }
   253  
   254  // addDeviceModelAndVisitors adds deviceModels and deviceVisitors in configMap
   255  func addDeviceModelAndVisitors(deviceModel *v1alpha1.DeviceModel, deviceProfile *types.DeviceProfile) {
   256  	model := &types.DeviceModel{}
   257  	model.Name = deviceModel.Name
   258  	model.Properties = make([]*types.Property, 0)
   259  	for _, ppt := range deviceModel.Spec.Properties {
   260  		property := &types.Property{}
   261  		property.Name = ppt.Name
   262  		property.Description = ppt.Description
   263  		if ppt.Type.Int != nil {
   264  			property.AccessMode = string(ppt.Type.Int.AccessMode)
   265  			property.DataType = DataTypeInt
   266  			property.DefaultValue = ppt.Type.Int.DefaultValue
   267  			property.Maximum = ppt.Type.Int.Maximum
   268  			property.Minimum = ppt.Type.Int.Minimum
   269  			property.Unit = ppt.Type.Int.Unit
   270  		} else if ppt.Type.String != nil {
   271  			property.AccessMode = string(ppt.Type.String.AccessMode)
   272  			property.DataType = DataTypeString
   273  			property.DefaultValue = ppt.Type.String.DefaultValue
   274  		}
   275  		model.Properties = append(model.Properties, property)
   276  	}
   277  	deviceProfile.DeviceModels = append(deviceProfile.DeviceModels, model)
   278  	for _, pptv := range deviceModel.Spec.PropertyVisitors {
   279  		propertyVisitor := &types.PropertyVisitor{}
   280  		propertyVisitor.Name = pptv.PropertyName
   281  		propertyVisitor.PropertyName = pptv.PropertyName
   282  		propertyVisitor.ModelName = deviceModel.Name
   283  		if pptv.Modbus != nil {
   284  			propertyVisitor.Protocol = Modbus
   285  			propertyVisitor.VisitorConfig = pptv.Modbus
   286  		} else if pptv.OpcUA != nil {
   287  			propertyVisitor.Protocol = OPCUA
   288  			propertyVisitor.VisitorConfig = pptv.OpcUA
   289  		} else if pptv.Bluetooth != nil {
   290  			propertyVisitor.Protocol = Bluetooth
   291  			propertyVisitor.VisitorConfig = pptv.Bluetooth
   292  		}
   293  		deviceProfile.PropertyVisitors = append(deviceProfile.PropertyVisitors, propertyVisitor)
   294  	}
   295  }
   296  
   297  // addDeviceInstanceAndProtocol adds deviceInstance and protocol in configMap
   298  func addDeviceInstanceAndProtocol(device *v1alpha1.Device, deviceProfile *types.DeviceProfile) {
   299  	deviceInstance := &types.DeviceInstance{}
   300  	deviceProtocol := &types.Protocol{}
   301  	deviceInstance.ID = device.Name
   302  	deviceInstance.Name = device.Name
   303  	deviceInstance.Model = device.Spec.DeviceModelRef.Name
   304  	var protocol string
   305  	if device.Spec.Protocol.OpcUA != nil {
   306  		protocol = OPCUA + "-" + device.Name
   307  		deviceInstance.Protocol = protocol
   308  		deviceProtocol.Name = protocol
   309  		deviceProtocol.Protocol = OPCUA
   310  		deviceProtocol.ProtocolConfig = device.Spec.Protocol.OpcUA
   311  	} else if device.Spec.Protocol.Modbus != nil && device.Spec.Protocol.Modbus.RTU != nil {
   312  		protocol = ModbusRTU + "-" + device.Name
   313  		deviceInstance.Protocol = protocol
   314  		deviceProtocol.Name = protocol
   315  		deviceProtocol.Protocol = ModbusRTU
   316  		deviceProtocol.ProtocolConfig = device.Spec.Protocol.Modbus.RTU
   317  	} else if device.Spec.Protocol.Modbus != nil && device.Spec.Protocol.Modbus.TCP != nil {
   318  		protocol = ModbusTCP + "-" + device.Name
   319  		deviceInstance.Protocol = protocol
   320  		deviceProtocol.Name = protocol
   321  		deviceProtocol.Protocol = ModbusTCP
   322  		deviceProtocol.ProtocolConfig = device.Spec.Protocol.Modbus.TCP
   323  	} else if device.Spec.Protocol.Bluetooth != nil {
   324  		protocol = Bluetooth + "-" + device.Name
   325  		deviceInstance.Protocol = protocol
   326  		deviceProtocol.Name = protocol
   327  		deviceProtocol.Protocol = Bluetooth
   328  		deviceProtocol.ProtocolConfig = device.Spec.Protocol.Bluetooth
   329  	} else {
   330  		klog.Warning("Device doesnt support valid protocol")
   331  	}
   332  	deviceProfile.DeviceInstances = append(deviceProfile.DeviceInstances, deviceInstance)
   333  	deviceProfile.Protocols = append(deviceProfile.Protocols, deviceProtocol)
   334  }
   335  
   336  // deviceAdded creates a device, adds in deviceManagers map, send a message to edge node if node selector is present.
   337  func (dc *DownstreamController) deviceAdded(device *v1alpha1.Device) {
   338  	dc.deviceManager.Device.Store(device.Name, device)
   339  	if len(device.Spec.NodeSelector.NodeSelectorTerms) != 0 && len(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions) != 0 && len(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values) != 0 {
   340  		dc.addToConfigMap(device)
   341  		edgeDevice := createDevice(device)
   342  		msg := model.NewMessage("")
   343  
   344  		resource, err := messagelayer.BuildResource(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values[0], "membership", "")
   345  		if err != nil {
   346  			klog.Warningf("Built message resource failed with error: %s", err)
   347  			return
   348  		}
   349  		msg.BuildRouter(constants.DeviceControllerModuleName, constants.GroupTwin, resource, model.UpdateOperation)
   350  
   351  		content := types.MembershipUpdate{AddDevices: []types.Device{
   352  			edgeDevice,
   353  		}}
   354  		content.EventID = uuid.NewV4().String()
   355  		content.Timestamp = time.Now().UnixNano() / 1e6
   356  		msg.Content = content
   357  
   358  		err = dc.messageLayer.Send(*msg)
   359  		if err != nil {
   360  			klog.Errorf("Failed to send device addition message %v due to error %v", msg, err)
   361  		}
   362  	}
   363  }
   364  
   365  // createDevice creates a device from CRD
   366  func createDevice(device *v1alpha1.Device) types.Device {
   367  	edgeDevice := types.Device{
   368  		// ID and name can be used as ID as we are using CRD and name(key in ETCD) will always be unique
   369  		ID:   device.Name,
   370  		Name: device.Name,
   371  	}
   372  
   373  	description, ok := device.Labels["description"]
   374  	if ok {
   375  		edgeDevice.Description = description
   376  	}
   377  
   378  	// TODO: optional is Always false, currently not present in CRD definition, need to add or remove from deviceTwin @ Edge
   379  	opt := false
   380  	optional := &opt
   381  	twin := make(map[string]*types.MsgTwin)
   382  	for i, dtwin := range device.Status.Twins {
   383  		expected := &types.TwinValue{}
   384  		expected.Value = &device.Status.Twins[i].Desired.Value
   385  		metadataType, ok := device.Status.Twins[i].Desired.Metadata["type"]
   386  		if !ok {
   387  			metadataType = "string"
   388  		}
   389  		timestamp := time.Now().UnixNano() / 1e6
   390  
   391  		metadata := &types.ValueMetadata{Timestamp: timestamp}
   392  		expected.Metadata = metadata
   393  
   394  		// TODO: how to manage versioning ??
   395  		cloudVersion, err := strconv.ParseInt(device.ResourceVersion, 10, 64)
   396  		if err != nil {
   397  			klog.Warningf("Failed to parse cloud version due to error %v", err)
   398  		}
   399  		twinVersion := &types.TwinVersion{CloudVersion: cloudVersion, EdgeVersion: 0}
   400  		msgTwin := &types.MsgTwin{
   401  			Expected:        expected,
   402  			Optional:        optional,
   403  			Metadata:        &types.TypeMetadata{Type: metadataType},
   404  			ExpectedVersion: twinVersion,
   405  		}
   406  		twin[dtwin.PropertyName] = msgTwin
   407  	}
   408  	edgeDevice.Twin = twin
   409  	return edgeDevice
   410  }
   411  
   412  // isDeviceUpdated checks if device is actually updated
   413  func isDeviceUpdated(oldTwin *v1alpha1.Device, newTwin *v1alpha1.Device) bool {
   414  	// does not care fields
   415  	oldTwin.ObjectMeta.ResourceVersion = newTwin.ObjectMeta.ResourceVersion
   416  	oldTwin.ObjectMeta.Generation = newTwin.ObjectMeta.Generation
   417  
   418  	// return true if ObjectMeta or Spec or Status changed, else false
   419  	return !reflect.DeepEqual(oldTwin.ObjectMeta, newTwin.ObjectMeta) || !reflect.DeepEqual(oldTwin.Spec, newTwin.Spec) || !reflect.DeepEqual(oldTwin.Status, newTwin.Status)
   420  }
   421  
   422  // isNodeSelectorUpdated checks if nodeSelector is updated
   423  func isNodeSelectorUpdated(oldTwin *v1.NodeSelector, newTwin *v1.NodeSelector) bool {
   424  	return !reflect.DeepEqual(oldTwin.NodeSelectorTerms, newTwin.NodeSelectorTerms)
   425  }
   426  
   427  // isProtocolConfigUpdated checks if protocol is updated
   428  func isProtocolConfigUpdated(oldTwin *v1alpha1.ProtocolConfig, newTwin *v1alpha1.ProtocolConfig) bool {
   429  	return !reflect.DeepEqual(oldTwin, newTwin)
   430  }
   431  
   432  // updateProtocolInConfigMap updates the protocol in the deviceProfile in configmap
   433  func (dc *DownstreamController) updateProtocolInConfigMap(device *v1alpha1.Device) {
   434  	if len(device.Spec.NodeSelector.NodeSelectorTerms) != 0 && len(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions) != 0 && len(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values) != 0 {
   435  		configMap, ok := dc.configMapManager.ConfigMap.Load(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values[0])
   436  		if !ok {
   437  			klog.Error("Failed to load configmap")
   438  			return
   439  		}
   440  
   441  		nodeConfigMap, ok := configMap.(*v1.ConfigMap)
   442  		if !ok {
   443  			klog.Error("Failed to assert to configmap")
   444  			return
   445  		}
   446  		dp, ok := nodeConfigMap.Data[DeviceProfileJSON]
   447  		if !ok || dp == "{}" {
   448  			// This case should never be hit as we delete empty configmaps
   449  			klog.Error("Failed to get deviceProfile from configmap data or deviceProfile is empty")
   450  			return
   451  		}
   452  
   453  		deviceProfile := &types.DeviceProfile{}
   454  		if err := json.Unmarshal([]byte(dp), deviceProfile); err != nil {
   455  			klog.Errorf("Failed to unmarshal due to error: %v", err)
   456  			return
   457  		}
   458  		var oldProtocol string
   459  		for _, devInst := range deviceProfile.DeviceInstances {
   460  			if device.Name == devInst.Name {
   461  				oldProtocol = devInst.Protocol
   462  				break
   463  			}
   464  		}
   465  
   466  		// delete the old protocol
   467  		for i, ptcl := range deviceProfile.Protocols {
   468  			if ptcl.Name == oldProtocol {
   469  				deviceProfile.Protocols = append(deviceProfile.Protocols[:i], deviceProfile.Protocols[i+1:]...)
   470  				break
   471  			}
   472  		}
   473  
   474  		// add new protocol
   475  		deviceProtocol := &types.Protocol{}
   476  		if device.Spec.Protocol.OpcUA != nil {
   477  			deviceProtocol = buildDeviceProtocol(OPCUA, device.Name, device.Spec.Protocol.OpcUA)
   478  		} else if device.Spec.Protocol.Modbus != nil && device.Spec.Protocol.Modbus.RTU != nil {
   479  			deviceProtocol = buildDeviceProtocol(ModbusRTU, device.Name, device.Spec.Protocol.Modbus.RTU)
   480  		} else if device.Spec.Protocol.Modbus != nil && device.Spec.Protocol.Modbus.TCP != nil {
   481  			deviceProtocol = buildDeviceProtocol(ModbusTCP, device.Name, device.Spec.Protocol.Modbus.TCP)
   482  		} else if device.Spec.Protocol.Bluetooth != nil {
   483  			deviceProtocol = buildDeviceProtocol(Bluetooth, device.Name, device.Spec.Protocol.Bluetooth)
   484  		} else {
   485  			klog.Warning("Unsupported device protocol")
   486  		}
   487  
   488  		// update the protocol in deviceInstance
   489  		for _, devInst := range deviceProfile.DeviceInstances {
   490  			if device.Name == devInst.Name {
   491  				devInst.Protocol = deviceProtocol.Name
   492  				break
   493  			}
   494  		}
   495  		deviceProfile.Protocols = append(deviceProfile.Protocols, deviceProtocol)
   496  
   497  		bytes, err := json.Marshal(deviceProfile)
   498  		if err != nil {
   499  			klog.Errorf("Failed to marshal deviceprofile: %v", deviceProfile)
   500  			return
   501  		}
   502  		nodeConfigMap.Data[DeviceProfileJSON] = string(bytes)
   503  		// store new config map
   504  		dc.configMapManager.ConfigMap.Store(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values[0], nodeConfigMap)
   505  		if _, err := dc.kubeClient.CoreV1().ConfigMaps(device.Namespace).Update(nodeConfigMap); err != nil {
   506  			klog.Errorf("Failed to update config map %v in namespace %v", nodeConfigMap, device.Namespace)
   507  			return
   508  		}
   509  	}
   510  }
   511  
   512  func buildDeviceProtocol(protocol, deviceName string, ProtocolConfig interface{}) *types.Protocol {
   513  	var deviceProtocol types.Protocol
   514  	deviceProtocol.Name = protocol + "-" + deviceName
   515  	deviceProtocol.Protocol = protocol
   516  	deviceProtocol.ProtocolConfig = ProtocolConfig
   517  	return &deviceProtocol
   518  }
   519  
   520  // deviceUpdated updates the map, check if device is actually updated.
   521  // If nodeSelector is updated, call add device for newNode, deleteDevice for old Node.
   522  // If twin is updated, send twin update message to edge
   523  func (dc *DownstreamController) deviceUpdated(device *v1alpha1.Device) {
   524  	value, ok := dc.deviceManager.Device.Load(device.Name)
   525  	dc.deviceManager.Device.Store(device.Name, device)
   526  	if ok {
   527  		cachedDevice := value.(*v1alpha1.Device)
   528  		if isDeviceUpdated(cachedDevice, device) {
   529  			// if node selector updated delete from old node and create in new node
   530  			if isNodeSelectorUpdated(cachedDevice.Spec.NodeSelector, device.Spec.NodeSelector) {
   531  				dc.deviceAdded(device)
   532  				deletedDevice := &v1alpha1.Device{ObjectMeta: cachedDevice.ObjectMeta,
   533  					Spec:     cachedDevice.Spec,
   534  					Status:   cachedDevice.Status,
   535  					TypeMeta: device.TypeMeta,
   536  				}
   537  				dc.deviceDeleted(deletedDevice)
   538  
   539  			} else if isProtocolConfigUpdated(&cachedDevice.Spec.Protocol, &device.Spec.Protocol) {
   540  				dc.updateProtocolInConfigMap(device)
   541  			} else {
   542  				// TODO: add an else if condition to check if DeviceModelReference has changed, if yes whether deviceModelReference exists
   543  				twin := make(map[string]*types.MsgTwin)
   544  				addUpdatedTwins(device.Status.Twins, twin, device.ResourceVersion)
   545  				addDeletedTwins(cachedDevice.Status.Twins, device.Status.Twins, twin, device.ResourceVersion)
   546  				msg := model.NewMessage("")
   547  
   548  				resource, err := messagelayer.BuildResource(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values[0], "device/"+device.Name+"/twin/cloud_updated", "")
   549  				if err != nil {
   550  					klog.Warningf("Built message resource failed with error: %s", err)
   551  					return
   552  				}
   553  				msg.BuildRouter(constants.DeviceControllerModuleName, constants.GroupTwin, resource, model.UpdateOperation)
   554  				content := types.DeviceTwinUpdate{Twin: twin}
   555  				content.EventID = uuid.NewV4().String()
   556  				content.Timestamp = time.Now().UnixNano() / 1e6
   557  				msg.Content = content
   558  
   559  				err = dc.messageLayer.Send(*msg)
   560  				if err != nil {
   561  					klog.Errorf("Failed to send deviceTwin message %v due to error %v", msg, err)
   562  				}
   563  			}
   564  		}
   565  	} else {
   566  		// If device not present in device map means it is not modified and added.
   567  		dc.deviceAdded(device)
   568  	}
   569  }
   570  
   571  // addDeletedTwins add deleted twins in the message
   572  func addDeletedTwins(oldTwin []v1alpha1.Twin, newTwin []v1alpha1.Twin, twin map[string]*types.MsgTwin, version string) {
   573  	opt := false
   574  	optional := &opt
   575  	for i, dtwin := range oldTwin {
   576  		if !ifTwinPresent(dtwin, newTwin) {
   577  			expected := &types.TwinValue{}
   578  			expected.Value = &oldTwin[i].Desired.Value
   579  			timestamp := time.Now().UnixNano() / 1e6
   580  
   581  			metadata := &types.ValueMetadata{Timestamp: timestamp}
   582  			expected.Metadata = metadata
   583  
   584  			// TODO: how to manage versioning ??
   585  			cloudVersion, err := strconv.ParseInt(version, 10, 64)
   586  			if err != nil {
   587  				klog.Warningf("Failed to parse cloud version due to error %v", err)
   588  			}
   589  			twinVersion := &types.TwinVersion{CloudVersion: cloudVersion, EdgeVersion: 0}
   590  			msgTwin := &types.MsgTwin{
   591  				Expected:        expected,
   592  				Optional:        optional,
   593  				Metadata:        &types.TypeMetadata{Type: "deleted"},
   594  				ExpectedVersion: twinVersion,
   595  			}
   596  			twin[dtwin.PropertyName] = msgTwin
   597  		}
   598  	}
   599  }
   600  
   601  // ifTwinPresent checks if twin is present in the array of twins
   602  func ifTwinPresent(twin v1alpha1.Twin, newTwins []v1alpha1.Twin) bool {
   603  	for _, dtwin := range newTwins {
   604  		if twin.PropertyName == dtwin.PropertyName {
   605  			return true
   606  		}
   607  	}
   608  	return false
   609  }
   610  
   611  // addUpdatedTwins is function of add updated twins to send to edge
   612  func addUpdatedTwins(newTwin []v1alpha1.Twin, twin map[string]*types.MsgTwin, version string) {
   613  	opt := false
   614  	optional := &opt
   615  	for i, dtwin := range newTwin {
   616  		expected := &types.TwinValue{}
   617  		expected.Value = &newTwin[i].Desired.Value
   618  		metadataType, ok := newTwin[i].Desired.Metadata["type"]
   619  		if !ok {
   620  			metadataType = "string"
   621  		}
   622  		timestamp := time.Now().UnixNano() / 1e6
   623  
   624  		metadata := &types.ValueMetadata{Timestamp: timestamp}
   625  		expected.Metadata = metadata
   626  
   627  		// TODO: how to manage versioning ??
   628  		cloudVersion, err := strconv.ParseInt(version, 10, 64)
   629  		if err != nil {
   630  			klog.Warningf("Failed to parse cloud version due to error %v", err)
   631  		}
   632  		twinVersion := &types.TwinVersion{CloudVersion: cloudVersion, EdgeVersion: 0}
   633  		msgTwin := &types.MsgTwin{
   634  			Expected:        expected,
   635  			Optional:        optional,
   636  			Metadata:        &types.TypeMetadata{Type: metadataType},
   637  			ExpectedVersion: twinVersion,
   638  		}
   639  		twin[dtwin.PropertyName] = msgTwin
   640  	}
   641  }
   642  
   643  // deleteFromConfigMap deletes a device from configMap
   644  func (dc *DownstreamController) deleteFromConfigMap(device *v1alpha1.Device) {
   645  	if len(device.Spec.NodeSelector.NodeSelectorTerms) != 0 && len(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions) != 0 && len(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values) != 0 {
   646  		configMap, ok := dc.configMapManager.ConfigMap.Load(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values[0])
   647  		if !ok {
   648  			return
   649  		}
   650  		nodeConfigMap, ok := configMap.(*v1.ConfigMap)
   651  		if !ok {
   652  			klog.Error("Failed to assert to configmap")
   653  			return
   654  		}
   655  
   656  		dc.deleteFromDeviceProfile(device, nodeConfigMap)
   657  
   658  		// no device is bound to the configMap, then remove the configMap directly.
   659  		if nodeConfigMap.Data[DeviceProfileJSON] == "{}" {
   660  			deleteOptions := &metav1.DeleteOptions{}
   661  			dc.kubeClient.CoreV1().ConfigMaps(device.Namespace).Delete(nodeConfigMap.Name, deleteOptions)
   662  			// remove from cache
   663  			dc.configMapManager.ConfigMap.Delete(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values[0])
   664  			return
   665  		}
   666  
   667  		// store new config map
   668  		dc.configMapManager.ConfigMap.Store(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values[0], nodeConfigMap)
   669  		if _, err := dc.kubeClient.CoreV1().ConfigMaps(device.Namespace).Update(nodeConfigMap); err != nil {
   670  			klog.Errorf("Failed to update config map %v in namespace %v", nodeConfigMap, device.Namespace)
   671  			return
   672  		}
   673  	}
   674  }
   675  
   676  // deleteFromDeviceProfile deletes a device from deviceProfile
   677  func (dc *DownstreamController) deleteFromDeviceProfile(device *v1alpha1.Device, configMap *v1.ConfigMap) {
   678  	dp, ok := configMap.Data[DeviceProfileJSON]
   679  	if !ok {
   680  		klog.Error("Device profile does not exist in the configmap")
   681  		return
   682  	}
   683  
   684  	deviceProfile := &types.DeviceProfile{}
   685  	err := json.Unmarshal([]byte(dp), deviceProfile)
   686  	if err != nil {
   687  		klog.Errorf("Failed to Unmarshal deviceprofile: %v", deviceProfile)
   688  		return
   689  	}
   690  	deleteDeviceInstanceAndProtocol(device, deviceProfile)
   691  
   692  	dm, ok := dc.deviceModelManager.DeviceModel.Load(device.Spec.DeviceModelRef.Name)
   693  	if !ok {
   694  		klog.Errorf("Failed to get device model %v", device.Spec.DeviceModelRef.Name)
   695  		return
   696  	}
   697  	deviceModel := dm.(*v1alpha1.DeviceModel)
   698  	// if model referenced by other devices, no need to delete the model
   699  	checkModelReferenced := false
   700  	for _, dvc := range deviceProfile.DeviceInstances {
   701  		if dvc.Model == deviceModel.Name {
   702  			checkModelReferenced = true
   703  			break
   704  		}
   705  	}
   706  	if checkModelReferenced != true {
   707  		deleteDeviceModelAndVisitors(deviceModel, deviceProfile)
   708  	}
   709  	bytes, err := json.Marshal(deviceProfile)
   710  	if err != nil {
   711  		klog.Errorf("Failed to marshal deviceprofile: %v", deviceProfile)
   712  		return
   713  	}
   714  	configMap.Data[DeviceProfileJSON] = string(bytes)
   715  }
   716  
   717  // deleteDeviceInstanceAndProtocol deletes deviceInstance and protocol from deviceProfile
   718  func deleteDeviceInstanceAndProtocol(device *v1alpha1.Device, deviceProfile *types.DeviceProfile) {
   719  	var protocol string
   720  	for i, devInst := range deviceProfile.DeviceInstances {
   721  		if device.Name == devInst.Name {
   722  			protocol = devInst.Protocol
   723  			deviceProfile.DeviceInstances[i] = deviceProfile.DeviceInstances[len(deviceProfile.DeviceInstances)-1]
   724  			deviceProfile.DeviceInstances[len(deviceProfile.DeviceInstances)-1] = nil
   725  			deviceProfile.DeviceInstances = deviceProfile.DeviceInstances[:len(deviceProfile.DeviceInstances)-1]
   726  			break
   727  		}
   728  	}
   729  
   730  	for i, ptcl := range deviceProfile.Protocols {
   731  		if ptcl.Name == protocol {
   732  			deviceProfile.Protocols[i] = deviceProfile.Protocols[len(deviceProfile.Protocols)-1]
   733  			deviceProfile.Protocols[len(deviceProfile.Protocols)-1] = nil
   734  			deviceProfile.Protocols = deviceProfile.Protocols[:len(deviceProfile.Protocols)-1]
   735  			return
   736  		}
   737  	}
   738  }
   739  
   740  // deleteDeviceModelAndVisitors deletes deviceModel and visitor from deviceProfile
   741  func deleteDeviceModelAndVisitors(deviceModel *v1alpha1.DeviceModel, deviceProfile *types.DeviceProfile) {
   742  	for i, dm := range deviceProfile.DeviceModels {
   743  		if dm.Name == deviceModel.Name {
   744  			deviceProfile.DeviceModels[i] = deviceProfile.DeviceModels[len(deviceProfile.DeviceModels)-1]
   745  			deviceProfile.DeviceModels[len(deviceProfile.DeviceModels)-1] = nil
   746  			deviceProfile.DeviceModels = deviceProfile.DeviceModels[:len(deviceProfile.DeviceModels)-1]
   747  			break
   748  		}
   749  	}
   750  
   751  	allVisitorsNotDeleted := true
   752  	for allVisitorsNotDeleted {
   753  		allVisitorsNotDeleted = false
   754  		for i, vst := range deviceProfile.PropertyVisitors {
   755  			if vst.ModelName == deviceModel.Name {
   756  				deviceProfile.PropertyVisitors[i] = deviceProfile.PropertyVisitors[len(deviceProfile.PropertyVisitors)-1]
   757  				deviceProfile.PropertyVisitors[len(deviceProfile.PropertyVisitors)-1] = nil
   758  				deviceProfile.PropertyVisitors = deviceProfile.PropertyVisitors[:len(deviceProfile.PropertyVisitors)-1]
   759  				allVisitorsNotDeleted = true
   760  				break
   761  			}
   762  		}
   763  	}
   764  }
   765  
   766  // deviceDeleted send a deleted message to the edgeNode and deletes the device from the deviceManager.Device map
   767  func (dc *DownstreamController) deviceDeleted(device *v1alpha1.Device) {
   768  	dc.deviceManager.Device.Delete(device.Name)
   769  	dc.deleteFromConfigMap(device)
   770  	edgeDevice := createDevice(device)
   771  	msg := model.NewMessage("")
   772  
   773  	if len(device.Spec.NodeSelector.NodeSelectorTerms) != 0 && len(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions) != 0 && len(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values) != 0 {
   774  		resource, err := messagelayer.BuildResource(device.Spec.NodeSelector.NodeSelectorTerms[0].MatchExpressions[0].Values[0], "membership", "")
   775  		msg.BuildRouter(constants.DeviceControllerModuleName, constants.GroupTwin, resource, model.UpdateOperation)
   776  
   777  		content := types.MembershipUpdate{RemoveDevices: []types.Device{
   778  			edgeDevice,
   779  		}}
   780  		content.EventID = uuid.NewV4().String()
   781  		content.Timestamp = time.Now().UnixNano() / 1e6
   782  		msg.Content = content
   783  		if err != nil {
   784  			klog.Warningf("Built message resource failed with error: %s", err)
   785  			return
   786  		}
   787  		err = dc.messageLayer.Send(*msg)
   788  		if err != nil {
   789  			klog.Errorf("Failed to send device addition message %v due to error %v", msg, err)
   790  		}
   791  	}
   792  }
   793  
   794  // Start DownstreamController
   795  func (dc *DownstreamController) Start() error {
   796  	klog.Info("Start downstream devicecontroller")
   797  
   798  	go dc.syncDeviceModel()
   799  
   800  	// Wait for adding all device model
   801  	// TODO need to think about sync
   802  	time.Sleep(1 * time.Second)
   803  	go dc.syncDevice()
   804  
   805  	return nil
   806  }
   807  
   808  // NewDownstreamController create a DownstreamController from config
   809  func NewDownstreamController() (*DownstreamController, error) {
   810  	cli, err := utils.KubeClient()
   811  	if err != nil {
   812  		klog.Warningf("Create kube client failed with error: %s", err)
   813  		return nil, err
   814  	}
   815  
   816  	config, err := utils.KubeConfig()
   817  	if err != nil {
   818  		klog.Warningf("Get kubeConfig error: %v", err)
   819  		return nil, err
   820  	}
   821  
   822  	crdcli, err := utils.NewCRDClient(config)
   823  	if err != nil {
   824  		klog.Warningf("Failed to create crd client: %s", err)
   825  		return nil, err
   826  	}
   827  	deviceManager, err := manager.NewDeviceManager(crdcli, v1.NamespaceAll)
   828  	if err != nil {
   829  		klog.Warningf("Create device manager failed with error: %s", err)
   830  		return nil, err
   831  	}
   832  
   833  	deviceModelManager, err := manager.NewDeviceModelManager(crdcli, v1.NamespaceAll)
   834  	if err != nil {
   835  		klog.Warningf("Create device manager failed with error: %s", err)
   836  		return nil, err
   837  	}
   838  
   839  	dc := &DownstreamController{
   840  		kubeClient:         cli,
   841  		deviceManager:      deviceManager,
   842  		deviceModelManager: deviceModelManager,
   843  		messageLayer:       messagelayer.NewContextMessageLayer(),
   844  		configMapManager:   manager.NewConfigMapManager(),
   845  	}
   846  	return dc, nil
   847  }