github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edge/test/integration/utils/helpers/helpers.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 helpers 18 19 import ( 20 "bytes" 21 "crypto/tls" 22 "database/sql" 23 "encoding/json" 24 "io" 25 "io/ioutil" 26 "net/http" 27 "time" 28 29 MQTT "github.com/eclipse/paho.mqtt.golang" 30 "github.com/onsi/gomega" 31 "k8s.io/api/core/v1" 32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 33 "k8s.io/apimachinery/pkg/types" 34 35 "github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dttype" 36 "github.com/kubeedge/kubeedge/edge/test/integration/utils" 37 "github.com/kubeedge/kubeedge/edge/test/integration/utils/common" 38 "github.com/kubeedge/kubeedge/edge/test/integration/utils/edge" 39 ) 40 41 //DeviceUpdate device update 42 type DeviceUpdate struct { 43 State string `json:"state,omitempty"` 44 Attributes map[string]*dttype.MsgAttr `json:"attributes"` 45 } 46 47 //Device the struct of device 48 type Device struct { 49 ID string `json:"id,omitempty"` 50 Name string `json:"name,omitempty"` 51 Description string `json:"description,omitempty"` 52 State string `json:"state,omitempty"` 53 LastOnline string `json:"last_online,omitempty"` 54 } 55 56 //Attribute Structure to read data from DB (Should match with the DB-table 'device_attr' schema) 57 type Attribute struct { 58 ID string `json:"id,omitempty"` 59 DeviceID string `json:"deviceid,omitempty"` 60 Name string `json:"name,omitempty"` 61 Description string `json:"description,omitempty"` 62 Value string `json:"value,omitempty"` 63 Optional bool `json:"optional,omitempty"` 64 Type string `json:"attr_type,omitempty"` 65 MetaData string `json:"metadata,omitempty"` 66 } 67 68 //Twin Structure to read data from DB (Should match with the DB-table 'device_twin' schema) 69 type TwinAttribute struct { 70 ID string `json:"id,omitempty"` 71 DeviceID string `json:"deviceid,omitempty"` 72 Name string `json:"name,omitempty"` 73 Description string `json:"description,omitempty"` 74 Expected string `json:"expected,omitempty"` 75 Actual string `json:"actual,omitempty"` 76 ExpectedMeta string `json:"expected_meta,omitempty"` 77 ActualMeta string `json:"actual_meta,omitempty"` 78 ExpectedVer string `json:"expected_version,omitempty"` 79 ActualVer string `json:"actual_version,omitempty"` 80 Optional bool `json:"optional,omitempty"` 81 Type string `json:"attr_type,omitempty"` 82 MetaData string `json:"metadata,omitempty"` 83 } 84 85 func GenerateDeviceID(deviceSuffix string) string { 86 return deviceSuffix + edge.GetRandomString(10) 87 } 88 89 //Function to Generate Device 90 func CreateDevice(deviceID string, deviceName string, deviceState string) dttype.Device { 91 device := dttype.Device{ 92 ID: deviceID, 93 Name: deviceName, 94 Description: "IntegrationTest", 95 State: deviceState, 96 Attributes: make(map[string]*dttype.MsgAttr), 97 Twin: make(map[string]*dttype.MsgTwin), 98 } 99 return device 100 } 101 102 //Function to add Device attribute to existing device 103 func AddDeviceAttribute(device dttype.Device, attributeName string, attributeValue string, attributeType string) { 104 var optional = true 105 var typeMeta = dttype.TypeMetadata{Type: attributeType} 106 var attribute = dttype.MsgAttr{Value: attributeValue, Optional: &optional, Metadata: &typeMeta} 107 device.Attributes[attributeName] = &attribute 108 } 109 110 //Function to add Twin attribute to existing device 111 func AddTwinAttribute(device dttype.Device, attributeName string, attributeValue string, attributeType string) { 112 value := attributeValue 113 optional := true 114 valueMeta := dttype.ValueMetadata{Timestamp: time.Now().Unix()} 115 typeMeta := dttype.TypeMetadata{Type: attributeType} 116 twinVersion := dttype.TwinVersion{CloudVersion: 1.0, EdgeVersion: 1.0} 117 twinValue := dttype.TwinValue{Value: &value, Metadata: &valueMeta} 118 msgTwin := dttype.MsgTwin{Expected: &twinValue, 119 Actual: &twinValue, 120 Optional: &optional, 121 Metadata: &typeMeta, 122 ExpectedVersion: &twinVersion, 123 ActualVersion: &twinVersion, 124 } 125 126 device.Twin[attributeName] = &msgTwin 127 } 128 129 //Function to access the edgecore DB and return the device state. 130 func GetDeviceStateFromDB(deviceID string) string { 131 var device Device 132 db, err := sql.Open("sqlite3", utils.DBFile) 133 if err != nil { 134 common.Fatalf("Open Sqlite DB failed : %v", err) 135 } 136 defer db.Close() 137 row, err := db.Query("SELECT * FROM device") 138 if err != nil { 139 common.Fatalf("Query Sqlite DB failed: %v", err) 140 } 141 defer row.Close() 142 for row.Next() { 143 err = row.Scan(&device.ID, &device.Name, &device.Description, &device.State, &device.LastOnline) 144 if err != nil { 145 common.Fatalf("Failed to scan DB rows: %v", err) 146 } 147 if string(device.ID) == deviceID { 148 break 149 } 150 } 151 return device.State 152 } 153 154 func GetTwinAttributesFromDB(deviceID string, Name string) TwinAttribute { 155 var twinAttribute TwinAttribute 156 db, err := sql.Open("sqlite3", utils.DBFile) 157 if err != nil { 158 common.Fatalf("Open Sqlite DB failed : %v", err) 159 } 160 defer db.Close() 161 row, err := db.Query("SELECT * FROM device_twin") 162 defer row.Close() 163 164 for row.Next() { 165 err = row.Scan(&twinAttribute.ID, 166 &twinAttribute.DeviceID, 167 &twinAttribute.Name, 168 &twinAttribute.Description, 169 &twinAttribute.Expected, 170 &twinAttribute.Actual, 171 &twinAttribute.ExpectedMeta, 172 &twinAttribute.ActualMeta, 173 &twinAttribute.ExpectedVer, 174 &twinAttribute.ActualVer, 175 &twinAttribute.Optional, 176 &twinAttribute.Type, 177 &twinAttribute.MetaData) 178 179 if err != nil { 180 common.Fatalf("Failed to scan DB rows: %v", err) 181 } 182 if string(twinAttribute.DeviceID) == deviceID && twinAttribute.Name == Name { 183 break 184 } 185 } 186 return twinAttribute 187 } 188 189 func GetDeviceAttributesFromDB(deviceID string, Name string) Attribute { 190 var attribute Attribute 191 192 db, err := sql.Open("sqlite3", utils.DBFile) 193 if err != nil { 194 common.Fatalf("Open Sqlite DB failed : %v", err) 195 } 196 defer db.Close() 197 row, err := db.Query("SELECT * FROM device_attr") 198 defer row.Close() 199 200 for row.Next() { 201 err = row.Scan(&attribute.ID, &attribute.DeviceID, &attribute.Name, &attribute.Description, &attribute.Value, &attribute.Optional, &attribute.Type, &attribute.MetaData) 202 if err != nil { 203 common.Fatalf("Failed to scan DB rows: %v", err) 204 } 205 if string(attribute.DeviceID) == deviceID && attribute.Name == Name { 206 break 207 } 208 } 209 return attribute 210 } 211 212 // HubclientInit create mqtt client config 213 func HubClientInit(server, clientID, username, password string) *MQTT.ClientOptions { 214 opts := MQTT.NewClientOptions().AddBroker(server).SetClientID(clientID).SetCleanSession(true) 215 if username != "" { 216 opts.SetUsername(username) 217 if password != "" { 218 opts.SetPassword(password) 219 } 220 } 221 tlsConfig := &tls.Config{InsecureSkipVerify: true, ClientAuth: tls.NoClientCert} 222 opts.SetTLSConfig(tlsConfig) 223 return opts 224 } 225 226 //function to handle device addition and deletion. 227 func HandleAddAndDeleteDevice(operation, testMgrEndPoint string, device dttype.Device) bool { 228 var httpMethod string 229 var payload dttype.MembershipUpdate 230 switch operation { 231 case "PUT": 232 httpMethod = http.MethodPut 233 payload = dttype.MembershipUpdate{AddDevices: []dttype.Device{ 234 device, 235 }} 236 case "DELETE": 237 httpMethod = http.MethodDelete 238 payload = dttype.MembershipUpdate{RemoveDevices: []dttype.Device{ 239 device, 240 }} 241 default: 242 common.Fatalf("operation %q is invalid", operation) 243 return false 244 } 245 246 respbytes, err := json.Marshal(payload) 247 if err != nil { 248 common.Fatalf("Payload marshalling failed: %v", err) 249 return false 250 } 251 252 req, err := http.NewRequest(httpMethod, testMgrEndPoint, bytes.NewBuffer(respbytes)) 253 if err != nil { 254 // handle error 255 common.Fatalf("Frame HTTP request failed: %v", err) 256 return false 257 } 258 259 client := &http.Client{} 260 req.Header.Set("Content-Type", "application/json; charset=utf-8") 261 t := time.Now() 262 resp, err := client.Do(req) 263 264 if err != nil { 265 // handle error 266 common.Fatalf("HTTP request is failed :%v", err) 267 return false 268 } 269 common.Infof("%s %s %v in %v", req.Method, req.URL, resp.Status, time.Now().Sub(t)) 270 return true 271 } 272 273 //HandleAddAndDeletePods is function to handle app deployment/delete deployment. 274 func HandleAddAndDeletePods(operation string, edgedpoint string, UID string, container []v1.Container, restartPolicy v1.RestartPolicy) bool { 275 var httpMethod string 276 switch operation { 277 case "PUT": 278 httpMethod = http.MethodPut 279 case "DELETE": 280 httpMethod = http.MethodDelete 281 default: 282 common.Fatalf("operation %q is invalid", operation) 283 return false 284 } 285 286 payload := &v1.Pod{ 287 TypeMeta: metav1.TypeMeta{Kind: "Job", APIVersion: "batch/v1"}, 288 ObjectMeta: metav1.ObjectMeta{Name: UID, Namespace: metav1.NamespaceDefault, UID: types.UID(UID)}, 289 Spec: v1.PodSpec{RestartPolicy: restartPolicy, Containers: container}, 290 } 291 respbytes, err := json.Marshal(payload) 292 if err != nil { 293 common.Fatalf("Payload marshalling failed: %v", err) 294 return false 295 } 296 297 req, err := http.NewRequest(httpMethod, edgedpoint, bytes.NewBuffer(respbytes)) 298 if err != nil { 299 // handle error 300 common.Fatalf("Frame HTTP request failed: %v", err) 301 return false 302 } 303 req.Header.Set("Content-Type", "application/json; charset=utf-8") 304 t := time.Now() 305 client := &http.Client{} 306 resp, err := client.Do(req) 307 if err != nil { 308 // handle error 309 common.Fatalf("HTTP request is failed :%v", err) 310 return false 311 } 312 common.Infof("%s %s %v in %v", req.Method, req.URL, resp.Status, time.Now().Sub(t)) 313 return true 314 } 315 316 //Function to get the pods from Edged 317 func GetPods(EdgedEndpoint string) (v1.PodList, error) { 318 var pods v1.PodList 319 var bytes io.Reader 320 client := &http.Client{} 321 t := time.Now() 322 req, err := http.NewRequest(http.MethodGet, EdgedEndpoint, bytes) 323 req.Header.Set("Content-Type", "application/json; charset=utf-8") 324 if err != nil { 325 common.Fatalf("Frame HTTP request failed: %v", err) 326 return pods, nil 327 } 328 resp, err := client.Do(req) 329 if err != nil { 330 common.Fatalf("Sending HTTP request failed: %v", err) 331 return pods, nil 332 } 333 common.Infof("%s %s %v in %v", req.Method, req.URL, resp.Status, time.Now().Sub(t)) 334 defer resp.Body.Close() 335 contents, err := ioutil.ReadAll(resp.Body) 336 if err != nil { 337 common.Fatalf("HTTP Response reading has failed: %v", err) 338 return pods, nil 339 } 340 err = json.Unmarshal(contents, &pods) 341 if err != nil { 342 common.Fatalf("Unmarshal HTTP Response has failed: %v", err) 343 return pods, nil 344 } 345 return pods, nil 346 } 347 348 //CheckPodRunningState is function to check the Pod state 349 func CheckPodRunningState(EdgedEndPoint, podname string) { 350 gomega.Eventually(func() string { 351 var status string 352 pods, _ := GetPods(EdgedEndPoint) 353 for index := range pods.Items { 354 pod := &pods.Items[index] 355 if podname == pod.Name { 356 status = string(pod.Status.Phase) 357 common.Infof("PodName: %s PodStatus: %s", pod.Name, pod.Status.Phase) 358 } 359 } 360 return status 361 }, "240s", "2s").Should(gomega.Equal("Running"), "Application Deployment is Unsuccessful, Pod has not come to Running State") 362 } 363 364 //CheckPodDeletion is function to check pod deletion 365 func CheckPodDeletion(EdgedEndPoint, UID string) { 366 gomega.Eventually(func() bool { 367 var IsExist = false 368 pods, _ := GetPods(EdgedEndPoint) 369 if len(pods.Items) > 0 { 370 for index := range pods.Items { 371 pod := &pods.Items[index] 372 common.Infof("PodName: %s PodStatus: %s", pod.Name, pod.Status.Phase) 373 if pod.Name == UID { 374 IsExist = true 375 } 376 } 377 } 378 return IsExist 379 }, "30s", "4s").Should(gomega.Equal(false), "Delete Application deployment is Unsuccessful, Pod has not come to Running State") 380 }