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

     1  package controller
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	v1 "k8s.io/api/core/v1"
     8  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     9  	"k8s.io/apimachinery/pkg/fields"
    10  	"k8s.io/apimachinery/pkg/labels"
    11  	"k8s.io/apimachinery/pkg/watch"
    12  	"k8s.io/client-go/kubernetes"
    13  	"k8s.io/klog"
    14  
    15  	beehiveContext "github.com/kubeedge/beehive/pkg/core/context"
    16  	"github.com/kubeedge/beehive/pkg/core/model"
    17  	"github.com/kubeedge/kubeedge/cloud/pkg/edgecontroller/config"
    18  	"github.com/kubeedge/kubeedge/cloud/pkg/edgecontroller/constants"
    19  	"github.com/kubeedge/kubeedge/cloud/pkg/edgecontroller/manager"
    20  	"github.com/kubeedge/kubeedge/cloud/pkg/edgecontroller/messagelayer"
    21  	"github.com/kubeedge/kubeedge/cloud/pkg/edgecontroller/utils"
    22  	common "github.com/kubeedge/kubeedge/common/constants"
    23  )
    24  
    25  // DownstreamController watch kubernetes api server and send change to edge
    26  type DownstreamController struct {
    27  	kubeClient   *kubernetes.Clientset
    28  	messageLayer messagelayer.MessageLayer
    29  
    30  	podManager *manager.PodManager
    31  
    32  	configmapManager *manager.ConfigMapManager
    33  
    34  	secretManager *manager.SecretManager
    35  
    36  	nodeManager *manager.NodesManager
    37  
    38  	serviceManager *manager.ServiceManager
    39  
    40  	endpointsManager *manager.EndpointsManager
    41  
    42  	lc *manager.LocationCache
    43  }
    44  
    45  func (dc *DownstreamController) syncPod() {
    46  	for {
    47  		select {
    48  		case <-beehiveContext.Done():
    49  			klog.Warning("Stop edgecontroller downstream syncPod loop")
    50  			return
    51  		case e := <-dc.podManager.Events():
    52  			pod, ok := e.Object.(*v1.Pod)
    53  			if !ok {
    54  				klog.Warningf("object type: %T unsupported", pod)
    55  				continue
    56  			}
    57  			if !dc.lc.IsEdgeNode(pod.Spec.NodeName) {
    58  				continue
    59  			}
    60  			msg := model.NewMessage("")
    61  			msg.SetResourceVersion(pod.ResourceVersion)
    62  			resource, err := messagelayer.BuildResource(pod.Spec.NodeName, pod.Namespace, model.ResourceTypePod, pod.Name)
    63  			if err != nil {
    64  				klog.Warningf("built message resource failed with error: %s", err)
    65  				continue
    66  			}
    67  			msg.Content = pod
    68  			switch e.Type {
    69  			case watch.Added:
    70  				msg.BuildRouter(constants.EdgeControllerModuleName, constants.GroupResource, resource, model.InsertOperation)
    71  				dc.lc.AddOrUpdatePod(*pod)
    72  			case watch.Deleted:
    73  				msg.BuildRouter(constants.EdgeControllerModuleName, constants.GroupResource, resource, model.DeleteOperation)
    74  			case watch.Modified:
    75  				msg.BuildRouter(constants.EdgeControllerModuleName, constants.GroupResource, resource, model.UpdateOperation)
    76  				dc.lc.AddOrUpdatePod(*pod)
    77  			default:
    78  				klog.Warningf("pod event type: %s unsupported", e.Type)
    79  			}
    80  			if err := dc.messageLayer.Send(*msg); err != nil {
    81  				klog.Warningf("send message failed with error: %s, operation: %s, resource: %s", err, msg.GetOperation(), msg.GetResource())
    82  			} else {
    83  				klog.Infof("send message successfully, operation: %s, resource: %s", msg.GetOperation(), msg.GetResource())
    84  			}
    85  		}
    86  	}
    87  }
    88  
    89  func (dc *DownstreamController) syncConfigMap() {
    90  	for {
    91  		select {
    92  		case <-beehiveContext.Done():
    93  			klog.Warning("Stop edgecontroller downstream syncConfigMap loop")
    94  			return
    95  		case e := <-dc.configmapManager.Events():
    96  			configMap, ok := e.Object.(*v1.ConfigMap)
    97  			if !ok {
    98  				klog.Warningf("object type: %T unsupported", configMap)
    99  				continue
   100  			}
   101  			var operation string
   102  			switch e.Type {
   103  			case watch.Added:
   104  				operation = model.InsertOperation
   105  			case watch.Modified:
   106  				operation = model.UpdateOperation
   107  			case watch.Deleted:
   108  				operation = model.DeleteOperation
   109  				dc.lc.DeleteConfigMap(configMap.Namespace, configMap.Name)
   110  			default:
   111  				// unsupported operation, no need to send to any node
   112  				klog.Warningf("config map event type: %s unsupported", e.Type)
   113  				continue // continue to next select
   114  			}
   115  
   116  			nodes := dc.lc.ConfigMapNodes(configMap.Namespace, configMap.Name)
   117  			klog.Infof("there are %d nodes need to sync config map, operation: %s", len(nodes), e.Type)
   118  			for _, n := range nodes {
   119  				msg := model.NewMessage("")
   120  				msg.SetResourceVersion(configMap.ResourceVersion)
   121  				resource, err := messagelayer.BuildResource(n, configMap.Namespace, model.ResourceTypeConfigmap, configMap.Name)
   122  				if err != nil {
   123  					klog.Warningf("build message resource failed with error: %s", err)
   124  					continue
   125  				}
   126  				msg.BuildRouter(constants.EdgeControllerModuleName, constants.GroupResource, resource, operation)
   127  				msg.Content = configMap
   128  				err = dc.messageLayer.Send(*msg)
   129  				if err != nil {
   130  					klog.Warningf("send message failed with error: %s, operation: %s, resource: %s", err, msg.GetOperation(), msg.GetResource())
   131  				} else {
   132  					klog.Infof("send message successfully, operation: %s, resource: %s", msg.GetOperation(), msg.GetResource())
   133  				}
   134  			}
   135  		}
   136  	}
   137  }
   138  
   139  func (dc *DownstreamController) syncSecret() {
   140  	for {
   141  		select {
   142  		case <-beehiveContext.Done():
   143  			klog.Warning("Stop edgecontroller downstream syncSecret loop")
   144  			return
   145  		case e := <-dc.secretManager.Events():
   146  			secret, ok := e.Object.(*v1.Secret)
   147  			if !ok {
   148  				klog.Warningf("object type: %T unsupported", secret)
   149  				continue
   150  			}
   151  			var operation string
   152  			switch e.Type {
   153  			case watch.Added:
   154  				// TODO: rollback when all edge upgrade to 2.1.6 or upper
   155  				fallthrough
   156  			case watch.Modified:
   157  				operation = model.UpdateOperation
   158  			case watch.Deleted:
   159  				operation = model.DeleteOperation
   160  				dc.lc.DeleteSecret(secret.Namespace, secret.Name)
   161  			default:
   162  				// unsupported operation, no need to send to any node
   163  				klog.Warningf("secret event type: %s unsupported", e.Type)
   164  				continue // continue to next select
   165  			}
   166  
   167  			nodes := dc.lc.SecretNodes(secret.Namespace, secret.Name)
   168  			klog.Infof("there are %d nodes need to sync secret, operation: %s", len(nodes), e.Type)
   169  			for _, n := range nodes {
   170  				msg := model.NewMessage("")
   171  				msg.SetResourceVersion(secret.ResourceVersion)
   172  				resource, err := messagelayer.BuildResource(n, secret.Namespace, model.ResourceTypeSecret, secret.Name)
   173  				if err != nil {
   174  					klog.Warningf("build message resource failed with error: %s", err)
   175  					continue
   176  				}
   177  				msg.BuildRouter(constants.EdgeControllerModuleName, constants.GroupResource, resource, operation)
   178  				msg.Content = secret
   179  				err = dc.messageLayer.Send(*msg)
   180  				if err != nil {
   181  					klog.Warningf("send message failed with error: %s, operation: %s, resource: %s", err, msg.GetOperation(), msg.GetResource())
   182  				} else {
   183  					klog.Infof("send message successfully, operation: %s, resource: %s", msg.GetOperation(), msg.GetResource())
   184  				}
   185  			}
   186  		}
   187  	}
   188  }
   189  
   190  func (dc *DownstreamController) syncEdgeNodes() {
   191  	for {
   192  		select {
   193  		case <-beehiveContext.Done():
   194  			klog.Warning("Stop edgecontroller downstream syncEdgeNodes loop")
   195  			return
   196  		case e := <-dc.nodeManager.Events():
   197  			node, ok := e.Object.(*v1.Node)
   198  			if !ok {
   199  				klog.Warningf("Object type: %T unsupported", node)
   200  				continue
   201  			}
   202  			switch e.Type {
   203  			case watch.Added:
   204  				fallthrough
   205  			case watch.Modified:
   206  				// When node comes to running, send all the service/endpoints/pods information to edge
   207  				for _, nsc := range node.Status.Conditions {
   208  					if nsc.Type == "Ready" {
   209  						status, ok := dc.lc.GetNodeStatus(node.ObjectMeta.Name)
   210  						dc.lc.UpdateEdgeNode(node.ObjectMeta.Name, string(nsc.Status))
   211  						if nsc.Status == "True" && (!ok || status != "True") {
   212  							// send all services to edge
   213  							msg := model.NewMessage("")
   214  							// TODO: what should in place of namespace and service when we are sending service list ?
   215  							resource, err := messagelayer.BuildResource(node.Name, "namespace", common.ResourceTypeServiceList, "service")
   216  							if err != nil {
   217  								klog.Warningf("Built message resource failed with error: %s", err)
   218  								break
   219  							}
   220  							msg.BuildRouter(constants.EdgeControllerModuleName, constants.GroupResource, resource, model.UpdateOperation)
   221  							svcs := dc.lc.GetAllServices()
   222  							msg.Content = svcs
   223  							if err := dc.messageLayer.Send(*msg); err != nil {
   224  								klog.Warningf("Send message failed with error: %s, operation: %s, resource: %s", err, msg.GetOperation(), msg.GetResource())
   225  							} else {
   226  								klog.Infof("Send message successfully, operation: %s, resource: %s", msg.GetOperation(), msg.GetResource())
   227  							}
   228  
   229  							for _, svc := range svcs {
   230  								pods, ok := dc.lc.GetServicePods(fmt.Sprintf("%s/%s", svc.Namespace, svc.Name))
   231  								if ok {
   232  									msg := model.NewMessage("")
   233  									resource, err := messagelayer.BuildResource(node.Name, svc.Namespace, model.ResourceTypePodlist, svc.Name)
   234  									if err != nil {
   235  										klog.Warningf("Built message resource failed with error: %v", err)
   236  										continue
   237  									}
   238  									msg.BuildRouter(constants.EdgeControllerModuleName, constants.GroupResource, resource, model.UpdateOperation)
   239  									msg.Content = pods
   240  									if err := dc.messageLayer.Send(*msg); err != nil {
   241  										klog.Warningf("Send message failed with error: %s, operation: %s, resource: %s", err, msg.GetOperation(), msg.GetResource())
   242  									} else {
   243  										klog.Infof("Send message successfully, operation: %s, resource: %s", msg.GetOperation(), msg.GetResource())
   244  									}
   245  								}
   246  							}
   247  
   248  							// send all endpoints to edge
   249  							msg = model.NewMessage("")
   250  							// TODO: what should in place of namespace and endpoints when we are sending endpoints list ?
   251  							resource, err = messagelayer.BuildResource(node.Name, "namespace", common.ResourceTypeEndpointsList, "endpoints")
   252  							if err != nil {
   253  								klog.Warningf("Built message resource failed with error: %s", err)
   254  								break
   255  							}
   256  							msg.BuildRouter(constants.EdgeControllerModuleName, constants.GroupResource, resource, model.UpdateOperation)
   257  							msg.Content = dc.lc.GetAllEndpoints()
   258  							if err := dc.messageLayer.Send(*msg); err != nil {
   259  								klog.Warningf("Send message failed with error: %s, operation: %s, resource: %s", err, msg.GetOperation(), msg.GetResource())
   260  							} else {
   261  								klog.Infof("Send message successfully, operation: %s, resource: %s", msg.GetOperation(), msg.GetResource())
   262  							}
   263  						}
   264  						break
   265  					}
   266  				}
   267  			case watch.Deleted:
   268  				dc.lc.DeleteNode(node.ObjectMeta.Name)
   269  			default:
   270  				// unsupported operation, no need to send to any node
   271  				klog.Warningf("Node event type: %s unsupported", e.Type)
   272  			}
   273  		}
   274  	}
   275  }
   276  
   277  func (dc *DownstreamController) syncService() {
   278  	var operation string
   279  	for {
   280  		select {
   281  		case <-beehiveContext.Done():
   282  			klog.Warning("Stop edgecontroller downstream syncService loop")
   283  			return
   284  		case e := <-dc.serviceManager.Events():
   285  			svc, ok := e.Object.(*v1.Service)
   286  			if !ok {
   287  				klog.Warningf("Object type: %T unsupported", svc)
   288  				continue
   289  			}
   290  			switch e.Type {
   291  			case watch.Added:
   292  				dc.lc.AddOrUpdateService(*svc)
   293  				operation = model.InsertOperation
   294  			case watch.Modified:
   295  				dc.lc.AddOrUpdateService(*svc)
   296  				operation = model.UpdateOperation
   297  			case watch.Deleted:
   298  				dc.lc.DeleteService(*svc)
   299  				operation = model.DeleteOperation
   300  			default:
   301  				// unsupported operation, no need to send to any node
   302  				klog.Warningf("Service event type: %s unsupported", e.Type)
   303  				continue
   304  			}
   305  
   306  			// send to all nodes
   307  			dc.lc.EdgeNodes.Range(func(key interface{}, value interface{}) bool {
   308  				nodeName, ok := key.(string)
   309  				if !ok {
   310  					klog.Warning("Failed to assert key to sting")
   311  					return true
   312  				}
   313  				msg := model.NewMessage("")
   314  				msg.SetResourceVersion(svc.ResourceVersion)
   315  				resource, err := messagelayer.BuildResource(nodeName, svc.Namespace, common.ResourceTypeService, svc.Name)
   316  				if err != nil {
   317  					klog.Warningf("Built message resource failed with error: %v", err)
   318  					return true
   319  				}
   320  				msg.BuildRouter(constants.EdgeControllerModuleName, constants.GroupResource, resource, operation)
   321  				msg.Content = svc
   322  				if err := dc.messageLayer.Send(*msg); err != nil {
   323  					klog.Warningf("Send message failed with error: %s, operation: %s, resource: %s", err, msg.GetOperation(), msg.GetResource())
   324  				} else {
   325  					klog.Infof("Send message successfully, operation: %s, resource: %s", msg.GetOperation(), msg.GetResource())
   326  				}
   327  				return true
   328  			})
   329  		}
   330  	}
   331  }
   332  
   333  func (dc *DownstreamController) syncEndpoints() {
   334  	var operation string
   335  	for {
   336  		select {
   337  		case <-beehiveContext.Done():
   338  			klog.Warning("Stop edgecontroller downstream syncEndpoints loop")
   339  			return
   340  		case e := <-dc.endpointsManager.Events():
   341  			eps, ok := e.Object.(*v1.Endpoints)
   342  			if !ok {
   343  				klog.Warningf("Object type: %T unsupported", eps)
   344  				continue
   345  			}
   346  
   347  			ok = true
   348  			switch e.Type {
   349  			case watch.Added:
   350  				dc.lc.AddOrUpdateEndpoints(*eps)
   351  				operation = model.InsertOperation
   352  			case watch.Modified:
   353  				ok = dc.lc.IsEndpointsUpdated(*eps)
   354  				dc.lc.AddOrUpdateEndpoints(*eps)
   355  				operation = model.UpdateOperation
   356  			case watch.Deleted:
   357  				dc.lc.DeleteEndpoints(*eps)
   358  				dc.lc.DeleteServicePods(*eps)
   359  				operation = model.DeleteOperation
   360  			default:
   361  				// unsupported operation, no need to send to any node
   362  				klog.Warningf("endpoints event type: %s unsupported", e.Type)
   363  				continue
   364  			}
   365  			// send to all nodes
   366  			if ok {
   367  				var listOptions metav1.ListOptions
   368  				var pods *v1.PodList
   369  				var err error
   370  				svc, ok := dc.lc.GetService(fmt.Sprintf("%s/%s", eps.Namespace, eps.Name))
   371  				if ok {
   372  					labelSelectorString := ""
   373  					for key, value := range svc.Spec.Selector {
   374  						labelSelectorString = labelSelectorString + key + "=" + value + ","
   375  					}
   376  					labelSelectorString = strings.TrimSuffix(labelSelectorString, ",")
   377  					listOptions = metav1.ListOptions{
   378  						LabelSelector: labelSelectorString,
   379  						Limit:         100,
   380  					}
   381  					pods, err = dc.kubeClient.CoreV1().Pods(svc.Namespace).List(listOptions)
   382  					if err == nil {
   383  						dc.lc.AddOrUpdateServicePods(fmt.Sprintf("%s/%s", svc.Namespace, svc.Name), pods.Items)
   384  					}
   385  				}
   386  				dc.lc.EdgeNodes.Range(func(key interface{}, value interface{}) bool {
   387  					nodeName, check := key.(string)
   388  					if !check {
   389  						klog.Warning("Failed to assert key to sting")
   390  						return true
   391  					}
   392  					msg := model.NewMessage("")
   393  					msg.SetResourceVersion(eps.ResourceVersion)
   394  					resource, err := messagelayer.BuildResource(nodeName, eps.Namespace, common.ResourceTypeEndpoints, eps.Name)
   395  					if err != nil {
   396  						klog.Warningf("Built message resource failed with error: %s", err)
   397  						return true
   398  					}
   399  					msg.BuildRouter(constants.EdgeControllerModuleName, constants.GroupResource, resource, operation)
   400  					msg.Content = eps
   401  					if err := dc.messageLayer.Send(*msg); err != nil {
   402  						klog.Warningf("Send message failed with error: %s, operation: %s, resource: %s", err, msg.GetOperation(), msg.GetResource())
   403  					} else {
   404  						klog.Infof("Send message successfully, operation: %s, resource: %s", msg.GetOperation(), msg.GetResource())
   405  					}
   406  					if operation != model.DeleteOperation && ok {
   407  						msg := model.NewMessage("")
   408  						resource, err := messagelayer.BuildResource(nodeName, svc.Namespace, model.ResourceTypePodlist, svc.Name)
   409  						if err != nil {
   410  							klog.Warningf("Built message resource failed with error: %v", err)
   411  							return true
   412  						}
   413  						msg.BuildRouter(constants.EdgeControllerModuleName, constants.GroupResource, resource, model.UpdateOperation)
   414  						msg.Content = pods.Items
   415  						if err := dc.messageLayer.Send(*msg); err != nil {
   416  							klog.Warningf("Send message failed with error: %s, operation: %s, resource: %s", err, msg.GetOperation(), msg.GetResource())
   417  						} else {
   418  							klog.Infof("Send message successfully, operation: %s, resource: %s", msg.GetOperation(), msg.GetResource())
   419  						}
   420  					}
   421  					return true
   422  				})
   423  			}
   424  		}
   425  	}
   426  }
   427  
   428  // Start DownstreamController
   429  func (dc *DownstreamController) Start() error {
   430  	klog.Info("start downstream controller")
   431  	// pod
   432  	go dc.syncPod()
   433  
   434  	// configmap
   435  	go dc.syncConfigMap()
   436  
   437  	// secret
   438  	go dc.syncSecret()
   439  
   440  	// nodes
   441  	go dc.syncEdgeNodes()
   442  
   443  	// service
   444  	go dc.syncService()
   445  
   446  	// endpoints
   447  	go dc.syncEndpoints()
   448  
   449  	return nil
   450  }
   451  
   452  // initLocating to know configmap and secret should send to which nodes
   453  func (dc *DownstreamController) initLocating() error {
   454  	var (
   455  		pods *v1.PodList
   456  		err  error
   457  	)
   458  
   459  	set := labels.Set{manager.NodeRoleKey: manager.NodeRoleValue}
   460  	selector := labels.SelectorFromSet(set)
   461  	nodes, err := dc.kubeClient.CoreV1().Nodes().List(metav1.ListOptions{LabelSelector: selector.String()})
   462  	if err != nil {
   463  		return err
   464  	}
   465  	var status string
   466  	for _, node := range nodes.Items {
   467  		for _, nsc := range node.Status.Conditions {
   468  			if nsc.Type == "Ready" {
   469  				status = string(nsc.Status)
   470  				break
   471  			}
   472  		}
   473  		dc.lc.UpdateEdgeNode(node.ObjectMeta.Name, status)
   474  	}
   475  
   476  	if !config.Config.EdgeSiteEnable {
   477  		pods, err = dc.kubeClient.CoreV1().Pods(v1.NamespaceAll).List(metav1.ListOptions{})
   478  	} else {
   479  		selector := fields.OneTermEqualSelector("spec.nodeName", config.Config.NodeName).String()
   480  		pods, err = dc.kubeClient.CoreV1().Pods(v1.NamespaceAll).List(metav1.ListOptions{FieldSelector: selector})
   481  	}
   482  	if err != nil {
   483  		return err
   484  	}
   485  	for _, p := range pods.Items {
   486  		if dc.lc.IsEdgeNode(p.Spec.NodeName) {
   487  			dc.lc.AddOrUpdatePod(p)
   488  		}
   489  	}
   490  
   491  	return nil
   492  }
   493  
   494  // NewDownstreamController create a DownstreamController from config
   495  func NewDownstreamController() (*DownstreamController, error) {
   496  	lc := &manager.LocationCache{}
   497  
   498  	cli, err := utils.KubeClient()
   499  	if err != nil {
   500  		klog.Warningf("create kube client failed with error: %s", err)
   501  		return nil, err
   502  	}
   503  
   504  	var nodeName = ""
   505  	if config.Config.EdgeSiteEnable {
   506  		if config.Config.NodeName == "" {
   507  			return nil, fmt.Errorf("kubeEdge node name is not provided in edgesite controller configuration")
   508  		}
   509  		nodeName = config.Config.NodeName
   510  	}
   511  
   512  	podManager, err := manager.NewPodManager(cli, v1.NamespaceAll, nodeName)
   513  	if err != nil {
   514  		klog.Warningf("create pod manager failed with error: %s", err)
   515  		return nil, err
   516  	}
   517  
   518  	configMapManager, err := manager.NewConfigMapManager(cli, v1.NamespaceAll)
   519  	if err != nil {
   520  		klog.Warningf("create configmap manager failed with error: %s", err)
   521  		return nil, err
   522  	}
   523  
   524  	secretManager, err := manager.NewSecretManager(cli, v1.NamespaceAll)
   525  	if err != nil {
   526  		klog.Warningf("create secret manager failed with error: %s", err)
   527  		return nil, err
   528  	}
   529  
   530  	nodesManager, err := manager.NewNodesManager(cli, v1.NamespaceAll)
   531  	if err != nil {
   532  		klog.Warningf("Create nodes manager failed with error: %s", err)
   533  		return nil, err
   534  	}
   535  
   536  	serviceManager, err := manager.NewServiceManager(cli, v1.NamespaceAll)
   537  	if err != nil {
   538  		klog.Warningf("Create service manager failed with error: %s", err)
   539  		return nil, err
   540  	}
   541  
   542  	endpointsManager, err := manager.NewEndpointsManager(cli, v1.NamespaceAll)
   543  	if err != nil {
   544  		klog.Warningf("Create endpoints manager failed with error: %s", err)
   545  		return nil, err
   546  	}
   547  
   548  	dc := &DownstreamController{
   549  		kubeClient:       cli,
   550  		podManager:       podManager,
   551  		configmapManager: configMapManager,
   552  		secretManager:    secretManager,
   553  		nodeManager:      nodesManager,
   554  		serviceManager:   serviceManager,
   555  		endpointsManager: endpointsManager,
   556  		messageLayer:     messagelayer.NewContextMessageLayer(),
   557  		lc:               lc,
   558  	}
   559  	if err := dc.initLocating(); err != nil {
   560  		return nil, err
   561  	}
   562  
   563  	return dc, nil
   564  }