devicecontroller源码阅读

Device Controller 源码阅读

设备控制器

设备控制器概述

设备控制器是KubeEdge的云组件,负责设备管理。KubeEdge中的设备管理是通过使用Kubernetes 自定义资源定义(CRD)来描述设备元数据/状态和设备控制器以在边缘和云之间同步这些设备更新来实现的。设备控制器启动两个独立的goroutine upstream controller,分别称为和downstream controller。这些不是单独的控制器,而是为了清楚起见在此命名。

设备控制器利用设备模型和设备实例来实现设备管理:

-设备模型:Adevice model描述设备公开的设备属性以及访问这些属性的属性访问者。设备模型就像一个可重用的模板,使用它可以创建和管理许多设备。可以在此处找到有关设备型号定义的详细信息。

-设备实例device实例代表实际的设备对象。就像是device model并引用模型中定义的属性。设备规格是静态的,而设备状态包含动态变化的数据,例如所需的设备属性状态和设备报告的状态。设备实例定义的详细信息可以在这里找到。

注意:可以在$ GOPATH / src / github.com / kubeedge / kubeedge / build / crd-samples / devices中找到一些协议的示例设备模型和设备实例。

设备型号

设备控制器执行的操作

以下是设备控制器执行的功能:

下游控制器:通过在K8S API服务器上进行监视,将设备更新从云同步到边缘节点

-上游控制器:使用以下命令将设备更新从边缘节点同步到云端设备双组件

上游控制器:

上游控制器从边缘节点监视更新,并将这些更新应用于云中的API服务器。更新和上游控制器可以采取的可能措施如下:

| 更新类型| 动作| | ————————————- | —————————————— |设备孪生报告状态已更新| 控制器在云中修补设备孪生属性的报告状态。|

设备上游控制器

将报告的设备孪生属性更新从边缘同步到云

映射器监视设备的更新,并通过MQTT代理将其报告给事件总线。事件总线将报告的设备状态发送到设备孪生,设备孪生将其存储在本地,然后将更新同步到云。设备控制器从边缘(通过cloudhub)监视设备更新,并更新云中报告的状态。

设备将边缘更新到云

下游控制器:

下游控制器根据K8S API服务器监视设备更新。以下是更新的分类,以及下游控制器可以采取的措施:

更新类型行动
创建新设备型号不适用
创建新设备控制器创建一个新的配置图,以存储设备属性和在与设备关联的设备模型中定义的访问者。此配置映射存储在etcd中。边缘控制器中现有的配置映射同步机制用于将配置映射同步到egde。在容器中运行的映射器应用程序可以获取更新的配置映射,并使用属性和访问者元数据来访问设备。设备控制器还向边缘节点报告设备双元数据更新。
设备节点成员资格已更新设备控制器将成员资格更新事件发送到边缘节点。
设备双期望状态已更新设备控制器将孪生更新事件发送到边缘节点。
设备已删除控制器发送设备孪生删除事件以删除与该设备关联的所有设备孪生。它还删除与设备关联的配置映射,并且此删除事件将同步到边缘。映射器应用程序有效地停止在设备上运行。

设备下游控制器

使用配置映射存储设备属性和访问者的想法是,这些元数据仅在边缘节点上运行的映射器应用程序才需要,以便连接到设备并收集数据。如果映射器作为容器运行,则可以将这些属性作为配置映射加载。下游控制器会监视云中对属性,访客等的任何添加,删除或更新,并在etcd中更新配置映射。如果映射器想要发现设备支持的属性,则可以从设备实例获取模型信息。同样,它可以获取协议信息以从设备实例连接到设备。一旦可以访问设备模型,就可以获取设备支持的属性。为了访问该属性,映射器需要获取相应的访客信息。可以从propertyVisitors列表中检索。最后,使用visitororConfig,映射器可以读取/写入与属性关联的数据。

将所需的设备双属性更新从云同步到边缘

设备将云更新到边缘设备控制器监视云中的设备更新并将其中继到边缘节点。这些更新由设备孪生本地存储。映射器通过MQTT代理获取这些更新,并根据更新在设备上运行。

源码阅读

1、代码入口

Device Controller在Cloudcore启动时注册,通过beehive消息通信框架调用Start()函数启动devicecontroller模块。

devicecontroller.Register(c.Modules.DeviceController, c.KubeAPIConfig)
2、结构定义、初始化
// DeviceController use beehive context message layer
type DeviceController struct {
   enable bool
}

func newDeviceController(enable bool) *DeviceController {
   return &DeviceController{
      enable: enable,
   }
}
3、启动
// Start controller
func (dc *DeviceController) Start() {
   downstream, err := controller.NewDownstreamController()
   if err != nil {
      klog.Fatalf("New downstream controller failed with error: %s", err)
   }
   upstream, err := controller.NewUpstreamController(downstream)
   if err != nil {
      klog.Fatalf("new upstream controller failed with error: %s", err)
   }

   if err := downstream.Start(); err != nil {
      klog.Fatalf("start downstream failed with error: %s", err)
   }
   // wait for downstream controller to start and load deviceModels and devices
   // TODO think about sync
   time.Sleep(1 * time.Second)
   if err := upstream.Start(); err != nil {
      klog.Fatalf("start upstream failed with error: %s", err)
   }
}
4、上游控制器
4.1 构造
// UpstreamController subscribe messages from edge and sync to k8s api server
type UpstreamController struct {
   crdClient    *rest.RESTClient
   messageLayer messagelayer.MessageLayer
   // message channel
   deviceStatusChan chan model.Message

   // downstream controller to update device status in cache
   dc *DownstreamController
}
4.2 初始化
// NewUpstreamController create UpstreamController from config
func NewUpstreamController(dc *DownstreamController) (*UpstreamController, error) {
   config, err := utils.KubeConfig()
   if err != nil {
      klog.Warningf("Failed to create kube client: %s", err)
      return nil, err
   }

   crdcli, err := utils.NewCRDClient(config)
   if err != nil {
      klog.Warningf("Failed to create crd client: %s", err)
      return nil, err
   }

   uc := &UpstreamController{
      crdClient:    crdcli,
      messageLayer: messagelayer.NewContextMessageLayer(),
      dc:           dc,
   }
   return uc, nil
}
4.3 启动
// Start UpstreamController
func (uc *UpstreamController) Start() error {
   klog.Info("Start upstream devicecontroller")

   uc.deviceStatusChan = make(chan model.Message, config.Config.Buffer.UpdateDeviceStatus)
   go uc.dispatchMessage()

   for i := 0; i < int(config.Config.Buffer.UpdateDeviceStatus); i++ {
      go uc.updateDeviceStatus()
   }
   return nil
}
func (uc *UpstreamController) dispatchMessage() {
   for {
      select {
      case <-beehiveContext.Done():
         klog.Info("Stop dispatchMessage")
         return
      default:
      }
      msg, err := uc.messageLayer.Receive()
      if err != nil {
         klog.Warningf("Receive message failed, %s", err)
         continue
      }

      klog.Infof("Dispatch message: %s", msg.GetID())

      resourceType, err := messagelayer.GetResourceType(msg.GetResource())
      if err != nil {
         klog.Warningf("Parse message: %s resource type with error: %s", msg.GetID(), err)
         continue
      }
      klog.Infof("Message: %s, resource type is: %s", msg.GetID(), resourceType)

      switch resourceType {
      case constants.ResourceTypeTwinEdgeUpdated:
         uc.deviceStatusChan <- msg
      default:
         klog.Warningf("Message: %s, with resource type: %s not intended for device controller", msg.GetID(), resourceType)
      }
   }
}
func (uc *UpstreamController) updateDeviceStatus() {
   for {
      select {
      case <-beehiveContext.Done():
         klog.Info("Stop updateDeviceStatus")
         return
      case msg := <-uc.deviceStatusChan:
         klog.Infof("Message: %s, operation is: %s, and resource is: %s", msg.GetID(), msg.GetOperation(), msg.GetResource())
         msgTwin, err := uc.unmarshalDeviceStatusMessage(msg)
         if err != nil {
            klog.Warningf("Unmarshall failed due to error %v", err)
            continue
         }
         deviceID, err := messagelayer.GetDeviceID(msg.GetResource())
         if err != nil {
            klog.Warning("Failed to get device id")
            continue
         }
         device, ok := uc.dc.deviceManager.Device.Load(deviceID)
         if !ok {
            klog.Warningf("Device %s does not exist in downstream controller", deviceID)
            continue
         }
         cacheDevice, ok := device.(*v1alpha2.Device)
         if !ok {
            klog.Warning("Failed to assert to CacheDevice type")
            continue
         }
         deviceStatus := &DeviceStatus{Status: cacheDevice.Status}
         for twinName, twin := range msgTwin.Twin {
            for i, cacheTwin := range deviceStatus.Status.Twins {
               if twinName == cacheTwin.PropertyName && twin.Actual != nil && twin.Actual.Value != nil {
                  reported := v1alpha2.TwinProperty{}
                  reported.Value = *twin.Actual.Value
                  reported.Metadata = make(map[string]string)
                  if twin.Actual.Metadata != nil {
                     reported.Metadata["timestamp"] = strconv.FormatInt(twin.Actual.Metadata.Timestamp, 10)
                  }
                  if twin.Metadata != nil {
                     reported.Metadata["type"] = twin.Metadata.Type
                  }
                  deviceStatus.Status.Twins[i].Reported = reported
                  break
               }
            }
         }

         // Store the status in cache so that when update is received by informer, it is not processed by downstream controller
         cacheDevice.Status = deviceStatus.Status
         uc.dc.deviceManager.Device.Store(deviceID, cacheDevice)

         body, err := json.Marshal(deviceStatus)
         if err != nil {
            klog.Errorf("Failed to marshal device status %v", deviceStatus)
            continue
         }
         result := uc.crdClient.Patch(MergePatchType).Namespace(cacheDevice.Namespace).Resource(ResourceTypeDevices).Name(deviceID).Body(body).Do(context.Background())
         if result.Error() != nil {
            klog.Errorf("Failed to patch device status %v of device %v in namespace %v", deviceStatus, deviceID, cacheDevice.Namespace)
            continue
         }
         //send confirm message to edge twin
         resMsg := model.NewMessage(msg.GetID())
         nodeID, err := messagelayer.GetNodeID(msg)
         if err != nil {
            klog.Warningf("Message: %s process failure, get node id failed with error: %s", msg.GetID(), err)
            continue
         }
         resource, err := messagelayer.BuildResource(nodeID, "twin", "")
         if err != nil {
            klog.Warningf("Message: %s process failure, build message resource failed with error: %s", msg.GetID(), err)
            continue
         }
         resMsg.BuildRouter(modules.DeviceControllerModuleName, constants.GroupTwin, resource, model.ResponseOperation)
         resMsg.Content = "OK"
         err = uc.messageLayer.Response(*resMsg)
         if err != nil {
            klog.Warningf("Message: %s process failure, response failed with error: %s", msg.GetID(), err)
            continue
         }
         klog.Infof("Message: %s process successfully", msg.GetID())
      }
   }
}
5、下游控制器
5.1 构造
// DownstreamController watch kubernetes api server and send change to edge
type DownstreamController struct {
   kubeClient   *kubernetes.Clientset
   messageLayer messagelayer.MessageLayer

   deviceManager      *manager.DeviceManager
   deviceModelManager *manager.DeviceModelManager
   configMapManager   *manager.ConfigMapManager

   crdClient *rest.RESTClient
}
5.2初始化
// NewDownstreamController create a DownstreamController from config
func NewDownstreamController() (*DownstreamController, error) {
   cli, err := utils.KubeClient()
   if err != nil {
      klog.Warningf("Create kube client failed with error: %s", err)
      return nil, err
   }

   config, err := utils.KubeConfig()
   if err != nil {
      klog.Warningf("Get kubeConfig error: %v", err)
      return nil, err
   }

   crdcli, err := utils.NewCRDClient(config)
   if err != nil {
      klog.Warningf("Failed to create crd client: %s", err)
      return nil, err
   }
   deviceManager, err := manager.NewDeviceManager(crdcli, v1.NamespaceAll)
   if err != nil {
      klog.Warningf("Create device manager failed with error: %s", err)
      return nil, err
   }

   deviceModelManager, err := manager.NewDeviceModelManager(crdcli, v1.NamespaceAll)
   if err != nil {
      klog.Warningf("Create device manager failed with error: %s", err)
      return nil, err
   }

   dc := &DownstreamController{
      kubeClient:         cli,
      deviceManager:      deviceManager,
      deviceModelManager: deviceModelManager,
      messageLayer:       messagelayer.NewContextMessageLayer(),
      configMapManager:   manager.NewConfigMapManager(),
   }
   return dc, nil
}
5.3 启动
// Start DownstreamController
func (dc *DownstreamController) Start() error {
   klog.Info("Start downstream devicecontroller")

   go dc.syncDeviceModel()

   // Wait for adding all device model
   // TODO need to think about sync
   time.Sleep(1 * time.Second)
   go dc.syncDevice()

   return nil
}
// syncDeviceModel is used to get events from informer
func (dc *DownstreamController) syncDeviceModel() {
   for {
      select {
      case <-beehiveContext.Done():
         klog.Info("stop syncDeviceModel")
         return
      case e := <-dc.deviceModelManager.Events():
         deviceModel, ok := e.Object.(*v1alpha2.DeviceModel)
         if !ok {
            klog.Warningf("object type: %T unsupported", deviceModel)
            continue
         }
         switch e.Type {
         case watch.Added:
            dc.deviceModelAdded(deviceModel)
         case watch.Deleted:
            dc.deviceModelDeleted(deviceModel)
         case watch.Modified:
            dc.deviceModelUpdated(deviceModel)
         default:
            klog.Warningf("deviceModel event type: %s unsupported", e.Type)
         }
      }
   }
}
// syncDevice is used to get device events from informer
func (dc *DownstreamController) syncDevice() {
   for {
      select {
      case <-beehiveContext.Done():
         klog.Info("Stop syncDevice")
         return
      case e := <-dc.deviceManager.Events():
         device, ok := e.Object.(*v1alpha2.Device)
         if !ok {
            klog.Warningf("Object type: %T unsupported", device)
            continue
         }
         switch e.Type {
         case watch.Added:
            dc.deviceAdded(device)
         case watch.Deleted:
            dc.deviceDeleted(device)
         case watch.Modified:
            dc.deviceUpdated(device)
         default:
            klog.Warningf("Device event type: %s unsupported", e.Type)
         }
      }
   }
}

klog.Warningf(“Object type: %T unsupported”, device)
continue
}
switch e.Type {
case watch.Added:
dc.deviceAdded(device)
case watch.Deleted:
dc.deviceDeleted(device)
case watch.Modified:
dc.deviceUpdated(device)
default:
klog.Warningf(“Device event type: %s unsupported”, e.Type)
}
}
}
}


参考链接:https://kubeedge.io/en/docs/components/cloud/device_controller/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值