github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/cloud/pkg/devicecontroller/controller/upstream.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 "strconv" 22 23 "k8s.io/client-go/rest" 24 "k8s.io/klog" 25 26 beehiveContext "github.com/kubeedge/beehive/pkg/core/context" 27 "github.com/kubeedge/beehive/pkg/core/model" 28 "github.com/kubeedge/kubeedge/cloud/pkg/apis/devices/v1alpha1" 29 "github.com/kubeedge/kubeedge/cloud/pkg/devicecontroller/config" 30 "github.com/kubeedge/kubeedge/cloud/pkg/devicecontroller/constants" 31 "github.com/kubeedge/kubeedge/cloud/pkg/devicecontroller/messagelayer" 32 "github.com/kubeedge/kubeedge/cloud/pkg/devicecontroller/types" 33 "github.com/kubeedge/kubeedge/cloud/pkg/devicecontroller/utils" 34 ) 35 36 // DeviceStatus is structure to patch device status 37 type DeviceStatus struct { 38 Status v1alpha1.DeviceStatus `json:"status"` 39 } 40 41 const ( 42 // MergePatchType is patch type 43 MergePatchType = "application/merge-patch+json" 44 // ResourceTypeDevices is plural of device resource in apiserver 45 ResourceTypeDevices = "devices" 46 ) 47 48 // UpstreamController subscribe messages from edge and sync to k8s api server 49 type UpstreamController struct { 50 crdClient *rest.RESTClient 51 messageLayer messagelayer.MessageLayer 52 // message channel 53 deviceStatusChan chan model.Message 54 55 // downstream controller to update device status in cache 56 dc *DownstreamController 57 } 58 59 // Start UpstreamController 60 func (uc *UpstreamController) Start() error { 61 klog.Info("Start upstream devicecontroller") 62 63 uc.deviceStatusChan = make(chan model.Message, config.Config.Buffer.UpdateDeviceStatus) 64 go uc.dispatchMessage() 65 66 for i := 0; i < int(config.Config.Buffer.UpdateDeviceStatus); i++ { 67 go uc.updateDeviceStatus() 68 } 69 return nil 70 } 71 72 func (uc *UpstreamController) dispatchMessage() { 73 for { 74 select { 75 case <-beehiveContext.Done(): 76 klog.Info("Stop dispatchMessage") 77 return 78 default: 79 } 80 msg, err := uc.messageLayer.Receive() 81 if err != nil { 82 klog.Warningf("Receive message failed, %s", err) 83 continue 84 } 85 86 klog.Infof("Dispatch message: %s", msg.GetID()) 87 88 resourceType, err := messagelayer.GetResourceType(msg.GetResource()) 89 if err != nil { 90 klog.Warningf("Parse message: %s resource type with error: %s", msg.GetID(), err) 91 continue 92 } 93 klog.Infof("Message: %s, resource type is: %s", msg.GetID(), resourceType) 94 95 switch resourceType { 96 case constants.ResourceTypeTwinEdgeUpdated: 97 uc.deviceStatusChan <- msg 98 default: 99 klog.Warningf("Message: %s, with resource type: %s not intended for device controller", msg.GetID(), resourceType) 100 } 101 } 102 } 103 104 func (uc *UpstreamController) updateDeviceStatus() { 105 for { 106 select { 107 case <-beehiveContext.Done(): 108 klog.Info("Stop updateDeviceStatus") 109 return 110 case msg := <-uc.deviceStatusChan: 111 klog.Infof("Message: %s, operation is: %s, and resource is: %s", msg.GetID(), msg.GetOperation(), msg.GetResource()) 112 msgTwin, err := uc.unmarshalDeviceStatusMessage(msg) 113 if err != nil { 114 klog.Warningf("Unmarshall failed due to error %v", err) 115 continue 116 } 117 deviceID, err := messagelayer.GetDeviceID(msg.GetResource()) 118 if err != nil { 119 klog.Warning("Failed to get device id") 120 continue 121 } 122 device, ok := uc.dc.deviceManager.Device.Load(deviceID) 123 if !ok { 124 klog.Warningf("Device %s does not exist in downstream controller", deviceID) 125 continue 126 } 127 cacheDevice, ok := device.(*v1alpha1.Device) 128 if !ok { 129 klog.Warning("Failed to assert to CacheDevice type") 130 continue 131 } 132 deviceStatus := &DeviceStatus{Status: cacheDevice.Status} 133 for twinName, twin := range msgTwin.Twin { 134 for i, cacheTwin := range deviceStatus.Status.Twins { 135 if twinName == cacheTwin.PropertyName && twin.Actual != nil && twin.Actual.Value != nil { 136 reported := v1alpha1.TwinProperty{} 137 reported.Value = *twin.Actual.Value 138 reported.Metadata = make(map[string]string) 139 if twin.Actual.Metadata != nil { 140 reported.Metadata["timestamp"] = strconv.FormatInt(twin.Actual.Metadata.Timestamp, 10) 141 } 142 if twin.Metadata != nil { 143 reported.Metadata["type"] = twin.Metadata.Type 144 } 145 deviceStatus.Status.Twins[i].Reported = reported 146 break 147 } 148 } 149 } 150 151 // Store the status in cache so that when update is received by informer, it is not processed by downstream controller 152 cacheDevice.Status = deviceStatus.Status 153 uc.dc.deviceManager.Device.Store(deviceID, cacheDevice) 154 155 body, err := json.Marshal(deviceStatus) 156 if err != nil { 157 klog.Errorf("Failed to marshal device status %v", deviceStatus) 158 continue 159 } 160 result := uc.crdClient.Patch(MergePatchType).Namespace(cacheDevice.Namespace).Resource(ResourceTypeDevices).Name(deviceID).Body(body).Do() 161 if result.Error() != nil { 162 klog.Errorf("Failed to patch device status %v of device %v in namespace %v", deviceStatus, deviceID, cacheDevice.Namespace) 163 continue 164 } 165 klog.Infof("Message: %s process successfully", msg.GetID()) 166 } 167 } 168 } 169 170 func (uc *UpstreamController) unmarshalDeviceStatusMessage(msg model.Message) (*types.DeviceTwinUpdate, error) { 171 content := msg.GetContent() 172 twinUpdate := &types.DeviceTwinUpdate{} 173 var contentData []byte 174 var err error 175 contentData, ok := content.([]byte) 176 if !ok { 177 contentData, err = json.Marshal(content) 178 if err != nil { 179 return nil, err 180 } 181 } 182 err = json.Unmarshal(contentData, twinUpdate) 183 if err != nil { 184 return nil, err 185 } 186 return twinUpdate, nil 187 } 188 189 // NewUpstreamController create UpstreamController from config 190 func NewUpstreamController(dc *DownstreamController) (*UpstreamController, error) { 191 config, err := utils.KubeConfig() 192 if err != nil { 193 klog.Warningf("Failed to create kube client: %s", err) 194 return nil, err 195 } 196 197 crdcli, err := utils.NewCRDClient(config) 198 if err != nil { 199 klog.Warningf("Failed to create crd client: %s", err) 200 return nil, err 201 } 202 203 uc := &UpstreamController{ 204 crdClient: crdcli, 205 messageLayer: messagelayer.NewContextMessageLayer(), 206 dc: dc, 207 } 208 return uc, nil 209 }