github.com/midokura/kubeedge@v1.2.0-mido.0/tests/performance/common/common.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 common
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"io"
    23  	"io/ioutil"
    24  	"math"
    25  	"net/http"
    26  	"os/exec"
    27  	"sort"
    28  	"strconv"
    29  	"strings"
    30  	"time"
    31  
    32  	. "github.com/onsi/gomega"
    33  	v1 "k8s.io/api/core/v1"
    34  
    35  	"github.com/kubeedge/kubeedge/tests/e2e/utils"
    36  	"github.com/kubeedge/kubeedge/tests/stubs/common/constants"
    37  	"github.com/kubeedge/kubeedge/tests/stubs/common/types"
    38  )
    39  
    40  //K8s resource handlers
    41  const (
    42  	AppHandler        = "/api/v1/namespaces/default/pods"
    43  	NodeHandler       = "/api/v1/nodes"
    44  	DeploymentHandler = "/apis/apps/v1/namespaces/default/deployments"
    45  	ConfigmapHandler  = "/api/v1/namespaces/default/configmaps"
    46  	ServiceHandler    = "/api/v1/namespaces/default/services"
    47  	NodelabelKey      = "k8snode"
    48  	NodelabelVal      = "kb-perf-node"
    49  )
    50  
    51  var (
    52  	chconfigmapRet      = make(chan error)
    53  	Deployments         []string
    54  	NodeInfo            = make(map[string][]string)
    55  	CloudConfigMap      string
    56  	CloudCoreDeployment string
    57  	ToTaint             bool
    58  	IsQuicProtocol      bool
    59  )
    60  
    61  func HandleCloudDeployment(cloudConfigMap, cloudCoreDeployment, apiserver2, confighdl, deploymenthdl, imgURL string, nodelimit int) error {
    62  	nodes := strconv.FormatInt(int64(nodelimit), 10)
    63  	cmd := exec.Command("bash", "-x", "scripts/update_configmap.sh", "create_cloud_config", "", apiserver2, cloudConfigMap, nodes)
    64  	err := utils.PrintCombinedOutput(cmd)
    65  	Expect(err).Should(BeNil())
    66  	go utils.HandleConfigmap(chconfigmapRet, http.MethodPost, confighdl, false)
    67  	ret := <-chconfigmapRet
    68  	Expect(ret).To(BeNil())
    69  	utils.ProtocolQuic = IsQuicProtocol
    70  	//Handle cloudCore deployment
    71  	go utils.HandleDeployment(true, false, http.MethodPost, deploymenthdl, cloudCoreDeployment, imgURL, "", cloudConfigMap, 1)
    72  
    73  	return nil
    74  }
    75  
    76  func CreateConfigMapforEdgeCore(cloudhub, cmHandler, nodeHandler string, numOfNodes int) {
    77  	//Create edgecore configMaps based on the users choice of edgecore deployment.
    78  	for i := 0; i < numOfNodes; i++ {
    79  		nodeName := "perf-node-" + utils.GetRandomString(10)
    80  		nodeSelector := "node-" + utils.GetRandomString(5)
    81  		configmap := "edgecore-configmap-" + utils.GetRandomString(5)
    82  		//Register EdgeNodes to K8s Master
    83  		go utils.RegisterNodeToMaster(nodeName, nodeHandler, nodeSelector)
    84  		cmd := exec.Command("bash", "-x", "scripts/update_configmap.sh", "create_edge_config", nodeName, cloudhub, configmap)
    85  		err := utils.PrintCombinedOutput(cmd)
    86  		Expect(err).Should(BeNil())
    87  		//Create ConfigMaps for Each EdgeNode created
    88  		go utils.HandleConfigmap(chconfigmapRet, http.MethodPost, cmHandler, true)
    89  		ret := <-chconfigmapRet
    90  		Expect(ret).To(BeNil())
    91  		//Store the ConfigMap against each edgenode
    92  		NodeInfo[nodeName] = append(NodeInfo[nodeName], configmap, nodeSelector)
    93  	}
    94  }
    95  
    96  func HandleEdgeCorePodDeployment(depHandler, imgURL, podHandler, nodeHandler string, numOfNodes int) v1.PodList {
    97  	replica := 1
    98  	//Create edgeCore deployments as per users configuration
    99  	for _, configmap := range NodeInfo {
   100  		UID := "edgecore-deployment-" + utils.GetRandomString(5)
   101  		go utils.HandleDeployment(false, true, http.MethodPost, depHandler, UID, imgURL, "", configmap[0], replica)
   102  		Deployments = append(Deployments, UID)
   103  	}
   104  	time.Sleep(2 * time.Second)
   105  	podlist, err := utils.GetPods(podHandler, "")
   106  	Expect(err).To(BeNil())
   107  	utils.CheckPodRunningState(podHandler, podlist)
   108  
   109  	//Check All EdgeNode are in Running state
   110  	Eventually(func() int {
   111  		count := 0
   112  		for edgenodeName := range NodeInfo {
   113  			status := utils.CheckNodeReadyStatus(nodeHandler, edgenodeName)
   114  			utils.Infof("Node Name: %v, Node Status: %v", edgenodeName, status)
   115  			if status == "Running" {
   116  				count++
   117  			}
   118  		}
   119  		return count
   120  	}, "1200s", "2s").Should(Equal(numOfNodes), "Nodes register to the k8s master is unsuccessfull !!")
   121  
   122  	return podlist
   123  }
   124  
   125  func HandleEdgeDeployment(cloudhub, depHandler, nodeHandler, cmHandler, imgURL, podHandler string, numOfNodes int) v1.PodList {
   126  	CreateConfigMapforEdgeCore(cloudhub, cmHandler, nodeHandler, numOfNodes)
   127  	podlist := HandleEdgeCorePodDeployment(depHandler, imgURL, podHandler, nodeHandler, numOfNodes)
   128  	return podlist
   129  }
   130  
   131  func DeleteEdgeDeployments(apiServerForRegisterNode, apiServerForDeployments string, nodes int) {
   132  	//delete confogMap
   133  	for _, configmap := range NodeInfo {
   134  		go utils.HandleConfigmap(chconfigmapRet, http.MethodDelete, apiServerForDeployments+ConfigmapHandler+"/"+configmap[0], false)
   135  		ret := <-chconfigmapRet
   136  		Expect(ret).To(BeNil())
   137  
   138  	}
   139  	//delete edgenode deployment
   140  	for _, depName := range Deployments {
   141  		go utils.HandleDeployment(true, true, http.MethodDelete, apiServerForDeployments+DeploymentHandler+"/"+depName, "", "", "", "", 0)
   142  	}
   143  	//delete edgenodes
   144  	for edgenodeName := range NodeInfo {
   145  		err := utils.DeRegisterNodeFromMaster(apiServerForRegisterNode+NodeHandler, edgenodeName)
   146  		if err != nil {
   147  			utils.Fatalf("DeRegisterNodeFromMaster failed: %v", err)
   148  		}
   149  	}
   150  	//Verify deployments, configmaps, nodes are deleted successfully
   151  	Eventually(func() int {
   152  		count := 0
   153  		for _, depName := range Deployments {
   154  			statusCode := utils.VerifyDeleteDeployment(apiServerForDeployments + DeploymentHandler + "/" + depName)
   155  			if statusCode == 404 {
   156  				count++
   157  			}
   158  		}
   159  		return count
   160  	}, "60s", "4s").Should(Equal(len(Deployments)), "EdgeNode deployments delete unsuccessfull !!")
   161  
   162  	Eventually(func() int {
   163  		count := 0
   164  		for _, configmap := range NodeInfo {
   165  			statusCode, _ := utils.GetConfigmap(apiServerForDeployments + ConfigmapHandler + "/" + configmap[0])
   166  			if statusCode == 404 {
   167  				count++
   168  			}
   169  		}
   170  		return count
   171  	}, "60s", "4s").Should(Equal(len(Deployments)), "EdgeNode configMaps delete unsuccessfull !!")
   172  
   173  	Eventually(func() int {
   174  		count := 0
   175  		for edgenodeName := range NodeInfo {
   176  			status := utils.CheckNodeDeleteStatus(apiServerForRegisterNode+NodeHandler, edgenodeName)
   177  			utils.Infof("Node Name: %v, Node Status: %v", edgenodeName, status)
   178  			if status == 404 {
   179  				count++
   180  			}
   181  		}
   182  		return count
   183  	}, "60s", "4s").Should(Equal(nodes), "EdgeNode deleton is unsuccessfull !!")
   184  	//Cleanup globals
   185  	NodeInfo = map[string][]string{}
   186  	Deployments = nil
   187  }
   188  
   189  func DeleteCloudDeployment(apiserver string) {
   190  	//delete cloud deployment
   191  	go utils.HandleDeployment(true, true, http.MethodDelete, apiserver+DeploymentHandler+"/"+CloudCoreDeployment, "", "", "", "", 0)
   192  	//delete cloud configMap
   193  	go utils.HandleConfigmap(chconfigmapRet, http.MethodDelete, apiserver+ConfigmapHandler+"/"+CloudConfigMap, false)
   194  	ret := <-chconfigmapRet
   195  	Expect(ret).To(BeNil())
   196  	//delete cloud svc
   197  	StatusCode := utils.DeleteSvc(apiserver + ServiceHandler + "/" + CloudCoreDeployment)
   198  	Expect(StatusCode).Should(Equal(http.StatusOK))
   199  }
   200  
   201  func ApplyLabel(nodeHandler string) error {
   202  	var isMasterNode bool
   203  	nodes := utils.GetNodes(nodeHandler)
   204  	for _, node := range nodes.Items {
   205  		isMasterNode = false
   206  		for key := range node.Labels {
   207  			if strings.Contains(key, "node-role.kubernetes.io/master") {
   208  				isMasterNode = true
   209  				break
   210  			}
   211  		}
   212  		if isMasterNode == false {
   213  			utils.ApplyLabelToNode(nodeHandler+"/"+node.Name, NodelabelKey, NodelabelVal)
   214  		}
   215  	}
   216  	return nil
   217  }
   218  
   219  // AddFakePod adds a fake pod
   220  func AddFakePod(ControllerHubURL string, pod types.FakePod) {
   221  	reqBody, err := json.Marshal(pod)
   222  	if err != nil {
   223  		utils.Fatalf("Unmarshal HTTP Response has failed: %v", err)
   224  	}
   225  
   226  	err, resp := SendHttpRequest(http.MethodPost,
   227  		ControllerHubURL+constants.PodResource,
   228  		bytes.NewBuffer(reqBody))
   229  	if err != nil {
   230  		utils.Fatalf("Frame HTTP request failed: %v", err)
   231  	}
   232  
   233  	if resp != nil {
   234  		defer resp.Body.Close()
   235  
   236  		contents, err := ioutil.ReadAll(resp.Body)
   237  		if err != nil {
   238  			utils.Fatalf("HTTP Response reading has failed: %v", err)
   239  		}
   240  
   241  		if contents != nil {
   242  			utils.Infof("AddPod response: %v", contents)
   243  		} else {
   244  			utils.Infof("AddPod response: nil")
   245  		}
   246  	}
   247  }
   248  
   249  // DeleteFakePod deletes a fake pod
   250  func DeleteFakePod(ControllerHubURL string, pod types.FakePod) {
   251  	err, resp := SendHttpRequest(http.MethodDelete,
   252  		ControllerHubURL+constants.PodResource+
   253  			"?name="+pod.Name+"&namespace="+pod.Namespace+"&nodename="+pod.NodeName,
   254  		nil)
   255  	if err != nil {
   256  		utils.Fatalf("Frame HTTP request failed: %v", err)
   257  	}
   258  
   259  	if resp != nil {
   260  		defer resp.Body.Close()
   261  
   262  		contents, err := ioutil.ReadAll(resp.Body)
   263  		if err != nil {
   264  			utils.Fatalf("HTTP Response reading has failed: %v", err)
   265  		}
   266  
   267  		if contents != nil {
   268  			utils.Infof("DeletePod response: %v", contents)
   269  		} else {
   270  			utils.Infof("DeletePod response: nil")
   271  		}
   272  	}
   273  }
   274  
   275  // ListFakePods lists all fake pods
   276  func ListFakePods(ControllerHubURL string) []types.FakePod {
   277  	pods := []types.FakePod{}
   278  	err, resp := SendHttpRequest(http.MethodGet, ControllerHubURL+constants.PodResource, nil)
   279  	if err != nil {
   280  		utils.Fatalf("Frame HTTP request failed: %v", err)
   281  	}
   282  
   283  	if resp != nil {
   284  		defer resp.Body.Close()
   285  
   286  		contents, err := ioutil.ReadAll(resp.Body)
   287  		if err != nil {
   288  			utils.Fatalf("HTTP Response reading has failed: %v", err)
   289  		}
   290  
   291  		err = json.Unmarshal(contents, &pods)
   292  		if err != nil {
   293  			utils.Fatalf("Unmarshal message content with error: %s", err)
   294  		}
   295  	}
   296  
   297  	utils.Infof("ListPods result: %d", len(pods))
   298  	return pods
   299  }
   300  
   301  // SendHttpRequest launches a http request
   302  func SendHttpRequest(method, reqApi string, body io.Reader) (error, *http.Response) {
   303  	var resp *http.Response
   304  	client := &http.Client{}
   305  	req, err := http.NewRequest(method, reqApi, body)
   306  	if err != nil {
   307  		utils.Fatalf("Frame HTTP request failed: %v", err)
   308  		return err, resp
   309  	}
   310  	req.Header.Set("Content-Type", "application/json")
   311  	t := time.Now()
   312  	resp, err = client.Do(req)
   313  	if err != nil {
   314  		utils.Fatalf("HTTP request is failed :%v", err)
   315  		return err, resp
   316  	}
   317  	if resp != nil {
   318  		utils.Infof("%s %s %v in %v", req.Method, req.URL, resp.Status, time.Now().Sub(t))
   319  	}
   320  	return nil, resp
   321  }
   322  
   323  // GetLatency calculates latency based on different percent
   324  func GetLatency(pods []types.FakePod) types.Latency {
   325  	latency := types.Latency{}
   326  	if len(pods) > 0 {
   327  		// Sort fake pods
   328  		sort.Stable(types.FakePodSort(pods))
   329  
   330  		// Get 50% throughputs latency
   331  		index50 := int(math.Ceil(float64(len(pods)) * 0.50))
   332  		latency.Percent50 = time.Duration(pods[index50-1].RunningTime - pods[index50-1].CreateTime)
   333  
   334  		// Get 90% throughputs latency
   335  		index90 := int(math.Ceil(float64(len(pods)) * 0.90))
   336  		latency.Percent90 = time.Duration(pods[index90-1].RunningTime - pods[index90-1].CreateTime)
   337  
   338  		// Get 99% throughputs latency
   339  		index99 := int(math.Ceil(float64(len(pods)) * 0.99))
   340  		latency.Percent99 = time.Duration(pods[index99-1].RunningTime - pods[index99-1].CreateTime)
   341  
   342  		// Get 100% throughputs latency
   343  		index100 := int(math.Ceil(float64(len(pods)) * 1.00))
   344  		latency.Percent100 = time.Duration(pods[index100-1].RunningTime - pods[index100-1].CreateTime)
   345  	}
   346  	return latency
   347  }