// tryUpdateNodeStatus tries to update node status to master. If ReconcileCBR0 // is set, this function will also confirm that cbr0 is configured correctly. func (kl *Kubelet) tryUpdateNodeStatus(tryNumber int) error { // In large clusters, GET and PUT operations on Node objects coming // from here are the majority of load on apiserver and etcd. // To reduce the load on etcd, we are serving GET operations from // apiserver cache (the data might be slightly delayed but it doesn't // seem to cause more confilict - the delays are pretty small). // If it result in a conflict, all retries are served directly from etcd. // TODO: Currently apiserver doesn't support serving GET operations // from its cache. Thus we are hacking it by issuing LIST with // field selector for the name of the node (field selectors with // specified name are handled efficiently by apiserver). Once // apiserver supports GET from cache, change it here. opts := v1.ListOptions{ FieldSelector: fields.Set{"metadata.name": string(kl.nodeName)}.AsSelector().String(), } if tryNumber == 0 { opts.ResourceVersion = "0" } nodes, err := kl.kubeClient.Core().Nodes().List(opts) if err != nil { return fmt.Errorf("error getting node %q: %v", kl.nodeName, err) } if len(nodes.Items) != 1 { return fmt.Errorf("no node instance returned for %q", kl.nodeName) } node := &nodes.Items[0] clonedNode, err := conversion.NewCloner().DeepCopy(node) if err != nil { return fmt.Errorf("error clone node %q: %v", kl.nodeName, err) } originalNode, ok := clonedNode.(*v1.Node) if !ok || originalNode == nil { return fmt.Errorf("failed to cast %q node object %#v to v1.Node", kl.nodeName, clonedNode) } kl.updatePodCIDR(node.Spec.PodCIDR) if err := kl.setNodeStatus(node); err != nil { return err } // Patch the current status on the API server updatedNode, err := nodeutil.PatchNodeStatus(kl.kubeClient, types.NodeName(kl.nodeName), originalNode, node) if err != nil { return err } // If update finishes sucessfully, mark the volumeInUse as reportedInUse to indicate // those volumes are already updated in the node's status kl.volumeManager.MarkVolumesAsReportedInUse(updatedNode.Status.VolumesInUse) return nil }
// tryUpdateNodeStatus tries to update node status to master. If ReconcileCBR0 // is set, this function will also confirm that cbr0 is configured correctly. func (kl *Kubelet) tryUpdateNodeStatus(tryNumber int) error { // In large clusters, GET and PUT operations on Node objects coming // from here are the majority of load on apiserver and etcd. // To reduce the load on etcd, we are serving GET operations from // apiserver cache (the data might be slightly delayed but it doesn't // seem to cause more conflict - the delays are pretty small). // If it result in a conflict, all retries are served directly from etcd. opts := metav1.GetOptions{} if tryNumber == 0 { opts.ResourceVersion = "0" } node, err := kl.kubeClient.Core().Nodes().Get(string(kl.nodeName), opts) if err != nil { return fmt.Errorf("error getting node %q: %v", kl.nodeName, err) } clonedNode, err := conversion.NewCloner().DeepCopy(node) if err != nil { return fmt.Errorf("error clone node %q: %v", kl.nodeName, err) } originalNode, ok := clonedNode.(*v1.Node) if !ok || originalNode == nil { return fmt.Errorf("failed to cast %q node object %#v to v1.Node", kl.nodeName, clonedNode) } kl.updatePodCIDR(node.Spec.PodCIDR) kl.setNodeStatus(node) // Patch the current status on the API server updatedNode, err := nodeutil.PatchNodeStatus(kl.kubeClient, types.NodeName(kl.nodeName), originalNode, node) if err != nil { return err } // If update finishes successfully, mark the volumeInUse as reportedInUse to indicate // those volumes are already updated in the node's status kl.volumeManager.MarkVolumesAsReportedInUse(updatedNode.Status.VolumesInUse) return nil }
// tryRegisterWithApiServer makes an attempt to register the given node with // the API server, returning a boolean indicating whether the attempt was // successful. If a node with the same name already exists, it reconciles the // value of the annotation for controller-managed attach-detach of attachable // persistent volumes for the node. If a node of the same name exists but has // a different externalID value, it attempts to delete that node so that a // later attempt can recreate it. func (kl *Kubelet) tryRegisterWithApiServer(node *v1.Node) bool { _, err := kl.kubeClient.Core().Nodes().Create(node) if err == nil { return true } if !apierrors.IsAlreadyExists(err) { glog.Errorf("Unable to register node %q with API server: %v", kl.nodeName, err) return false } existingNode, err := kl.kubeClient.Core().Nodes().Get(string(kl.nodeName), metav1.GetOptions{}) if err != nil { glog.Errorf("Unable to register node %q with API server: error getting existing node: %v", kl.nodeName, err) return false } if existingNode == nil { glog.Errorf("Unable to register node %q with API server: no node instance returned", kl.nodeName) return false } clonedNode, err := conversion.NewCloner().DeepCopy(existingNode) if err != nil { glog.Errorf("Unable to clone %q node object %#v: %v", kl.nodeName, existingNode, err) return false } originalNode, ok := clonedNode.(*v1.Node) if !ok || originalNode == nil { glog.Errorf("Unable to cast %q node object %#v to v1.Node", kl.nodeName, clonedNode) return false } if existingNode.Spec.ExternalID == node.Spec.ExternalID { glog.Infof("Node %s was previously registered", kl.nodeName) // Edge case: the node was previously registered; reconcile // the value of the controller-managed attach-detach // annotation. requiresUpdate := kl.reconcileCMADAnnotationWithExistingNode(node, existingNode) if requiresUpdate { if _, err := nodeutil.PatchNodeStatus(kl.kubeClient, types.NodeName(kl.nodeName), originalNode, existingNode); err != nil { glog.Errorf("Unable to reconcile node %q with API server: error updating node: %v", kl.nodeName, err) return false } } return true } glog.Errorf( "Previously node %q had externalID %q; now it is %q; will delete and recreate.", kl.nodeName, node.Spec.ExternalID, existingNode.Spec.ExternalID, ) if err := kl.kubeClient.Core().Nodes().Delete(node.Name, nil); err != nil { glog.Errorf("Unable to register node %q with API server: error deleting old node: %v", kl.nodeName, err) } else { glog.Info("Deleted old node object %q", kl.nodeName) } return false }