func (t *Tester) testUpdateFailsOnVersionTooOld(obj runtime.Object, createFn CreateFunc, getFn GetFunc) { ctx := t.TestContext() foo := copyOrDie(obj) t.setObjectMeta(foo, t.namer(3)) if err := createFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } storedFoo, err := getFn(ctx, foo) if err != nil { t.Errorf("unexpected error: %v", err) } older := copyOrDie(storedFoo) olderMeta := t.getObjectMetaOrFail(older) olderMeta.ResourceVersion = "1" _, _, err = t.storage.(rest.Updater).Update(t.TestContext(), olderMeta.Name, rest.DefaultUpdatedObjectInfo(older, api.Scheme)) if err == nil { t.Errorf("Expected an error, but we didn't get one") } else if !errors.IsConflict(err) { t.Errorf("Expected Conflict error, got '%v'", err) } }
// updateVolume runs in worker thread and handles "volume added", // "volume updated" and "periodic sync" events. func (ctrl *PersistentVolumeController) updateVolume(volume *v1.PersistentVolume) { if deleted := ctrl.upgradeVolumeFrom1_2(volume); deleted { // volume deleted return } // Store the new volume version in the cache and do not process it if this // is an old version. new, err := ctrl.storeVolumeUpdate(volume) if err != nil { glog.Errorf("%v", err) } if !new { return } err = ctrl.syncVolume(volume) if err != nil { if errors.IsConflict(err) { // Version conflict error happens quite often and the controller // recovers from it easily. glog.V(3).Infof("could not sync volume %q: %+v", volume.Name, err) } else { glog.Errorf("could not sync volume %q: %+v", volume.Name, err) } } }
func (cc *clusterClientCache) persistFedServiceUpdate(cachedService *cachedService, fedClient fedclientset.Interface) error { service := cachedService.lastState glog.V(5).Infof("Persist federation service status %s/%s", service.Namespace, service.Name) var err error for i := 0; i < clientRetryCount; i++ { _, err := fedClient.Core().Services(service.Namespace).Get(service.Name, metav1.GetOptions{}) if errors.IsNotFound(err) { glog.Infof("Not persisting update to service '%s/%s' that no longer exists: %v", service.Namespace, service.Name, err) return nil } _, err = fedClient.Core().Services(service.Namespace).UpdateStatus(service) if err == nil { glog.V(2).Infof("Successfully update service %s/%s to federation apiserver", service.Namespace, service.Name) return nil } if errors.IsNotFound(err) { glog.Infof("Not persisting update to service '%s/%s' that no longer exists: %v", service.Namespace, service.Name, err) return nil } if errors.IsConflict(err) { glog.V(4).Infof("Not persisting update to service '%s/%s' that has been changed since we received it: %v", service.Namespace, service.Name, err) return err } time.Sleep(cachedService.nextFedUpdateDelay()) } return err }
func updateIngressOrFail(clientset *fedclientset.Clientset, namespace string) (newIng *v1beta1.Ingress) { var err error if clientset == nil || len(namespace) == 0 { Fail(fmt.Sprintf("Internal error: invalid parameters passed to createIngressOrFail: clientset: %v, namespace: %v", clientset, namespace)) } ingress := &v1beta1.Ingress{ ObjectMeta: metav1.ObjectMeta{ Name: FederatedIngressName, }, Spec: v1beta1.IngressSpec{ Backend: &v1beta1.IngressBackend{ ServiceName: "updated-testingress-service", ServicePort: intstr.FromInt(80), }, }, } err = waitForFederatedIngressExists(clientset, namespace, FederatedIngressName, FederatedIngressTimeout) if err != nil { framework.Failf("failed to get ingress %q: %v", FederatedIngressName, err) } for i := 0; i < MaxRetriesOnFederatedApiserver; i++ { newIng, err = clientset.Extensions().Ingresses(namespace).Update(ingress) if err == nil { framework.DescribeIng(namespace) return newIng } if !errors.IsConflict(err) && !errors.IsServerTimeout(err) { framework.Failf("failed to update ingress %q: %v", FederatedIngressName, err) } } framework.Failf("too many retries updating ingress %q", FederatedIngressName) return nil }
func updateDaemonSetOrFail(clientset *fedclientset.Clientset, namespace string) *v1beta1.DaemonSet { if clientset == nil || len(namespace) == 0 { Fail(fmt.Sprintf("Internal error: invalid parameters passed to updateDaemonSetOrFail: clientset: %v, namespace: %v", clientset, namespace)) } var newDaemonSet *v1beta1.DaemonSet for retryCount := 0; retryCount < FederatedDaemonSetMaxRetries; retryCount++ { daemonset, err := clientset.Extensions().DaemonSets(namespace).Get(FederatedDaemonSetName, metav1.GetOptions{}) if err != nil { framework.Failf("failed to get daemonset %q: %v", FederatedDaemonSetName, err) } // Update one of the data in the daemonset. daemonset.Annotations = map[string]string{"ccc": "ddd"} newDaemonSet, err = clientset.Extensions().DaemonSets(namespace).Update(daemonset) if err == nil { return newDaemonSet } if !errors.IsConflict(err) && !errors.IsServerTimeout(err) { framework.Failf("failed to update daemonset %q: %v", FederatedDaemonSetName, err) } } framework.Failf("too many retries updating daemonset %q", FederatedDaemonSetName) return newDaemonSet }
func TestEtcdCreateWithConflict(t *testing.T) { storage, bindingStorage, _, server := newStorage(t) defer server.Terminate(t) defer storage.Store.DestroyFunc() ctx := genericapirequest.NewDefaultContext() _, err := storage.Create(ctx, validNewPod()) if err != nil { t.Fatalf("unexpected error: %v", err) } // Suddenly, a wild scheduler appears: binding := api.Binding{ ObjectMeta: metav1.ObjectMeta{ Namespace: api.NamespaceDefault, Name: "foo", Annotations: map[string]string{"label1": "value1"}, }, Target: api.ObjectReference{Name: "machine"}, } _, err = bindingStorage.Create(ctx, &binding) if err != nil { t.Fatalf("unexpected error: %v", err) } _, err = bindingStorage.Create(ctx, &binding) if err == nil || !errors.IsConflict(err) { t.Fatalf("expected resource conflict error, not: %v", err) } }
// This test the fast-fail path. We test that the precondition gets verified // again before deleting the object in tests of pkg/storage/etcd. func (t *Tester) testDeleteWithUID(obj runtime.Object, createFn CreateFunc, getFn GetFunc, isNotFoundFn IsErrorFunc) { ctx := t.TestContext() foo := copyOrDie(obj) t.setObjectMeta(foo, t.namer(1)) objectMeta := t.getObjectMetaOrFail(foo) objectMeta.UID = types.UID("UID0000") if err := createFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } obj, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewPreconditionDeleteOptions("UID1111")) if err == nil || !errors.IsConflict(err) { t.Errorf("unexpected error: %v", err) } obj, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewPreconditionDeleteOptions("UID0000")) if err != nil { t.Errorf("unexpected error: %v", err) } if !t.returnDeletedObject { if status, ok := obj.(*metav1.Status); !ok { t.Errorf("expected status of delete, got %v", status) } else if status.Status != metav1.StatusSuccess { t.Errorf("expected success, got: %v", status.Status) } } _, err = getFn(ctx, foo) if err == nil || !isNotFoundFn(err) { t.Errorf("unexpected error: %v", err) } }
func updateSecretOrFail(clientset *fedclientset.Clientset, nsName string, secretName string) *v1.Secret { if clientset == nil || len(nsName) == 0 { Fail(fmt.Sprintf("Internal error: invalid parameters passed to updateSecretOrFail: clientset: %v, namespace: %v", clientset, nsName)) } var newSecret *v1.Secret for retryCount := 0; retryCount < MaxRetries; retryCount++ { secret, err := clientset.Core().Secrets(nsName).Get(secretName, metav1.GetOptions{}) if err != nil { framework.Failf("failed to get secret %q: %v", secretName, err) } // Update one of the data in the secret. secret.Data = map[string][]byte{ "key": []byte("value"), } newSecret, err = clientset.Core().Secrets(nsName).Update(secret) if err == nil { return newSecret } if !errors.IsConflict(err) && !errors.IsServerTimeout(err) { framework.Failf("failed to update secret %q: %v", secretName, err) } } framework.Failf("too many retries updating secret %q", secretName) return newSecret }
func attemptToUpdateMasterRoleLabelsAndTaints(client *clientset.Clientset, schedulable bool) error { n, err := findMyself(client) if err != nil { return err } n.ObjectMeta.Labels[metav1.NodeLabelKubeadmAlphaRole] = metav1.NodeLabelRoleMaster if !schedulable { taintsAnnotation, _ := json.Marshal([]v1.Taint{{Key: "dedicated", Value: "master", Effect: "NoSchedule"}}) n.ObjectMeta.Annotations[v1.TaintsAnnotationKey] = string(taintsAnnotation) } if _, err := client.Nodes().Update(n); err != nil { if apierrs.IsConflict(err) { fmt.Println("[apiclient] Temporarily unable to update master node metadata due to conflict (will retry)") time.Sleep(apiCallRetryInterval) attemptToUpdateMasterRoleLabelsAndTaints(client, schedulable) } else { return err } } return nil }
// RemoveLabelOffNode is for cleaning up labels temporarily added to node, // won't fail if target label doesn't exist or has been removed. func RemoveLabelOffNode(c clientset.Interface, nodeName string, labelKeys []string) error { var node *v1.Node var err error for attempt := 0; attempt < retries; attempt++ { node, err = c.Core().Nodes().Get(nodeName, metav1.GetOptions{}) if err != nil { return err } if node.Labels == nil { return nil } for _, labelKey := range labelKeys { if node.Labels == nil || len(node.Labels[labelKey]) == 0 { break } delete(node.Labels, labelKey) } _, err = c.Core().Nodes().Update(node) if err != nil { if !apierrs.IsConflict(err) { return err } else { glog.V(2).Infof("Conflict when trying to remove a labels %v from %v", labelKeys, nodeName) } } else { break } time.Sleep(100 * time.Millisecond) } return err }
func (s *ServiceController) persistUpdate(service *v1.Service) error { var err error for i := 0; i < clientRetryCount; i++ { _, err = s.kubeClient.Core().Services(service.Namespace).UpdateStatus(service) if err == nil { return nil } // If the object no longer exists, we don't want to recreate it. Just bail // out so that we can process the delete, which we should soon be receiving // if we haven't already. if errors.IsNotFound(err) { glog.Infof("Not persisting update to service '%s/%s' that no longer exists: %v", service.Namespace, service.Name, err) return nil } // TODO: Try to resolve the conflict if the change was unrelated to load // balancer status. For now, just pass it up the stack. if errors.IsConflict(err) { return fmt.Errorf("Not persisting update to service '%s/%s' that has been changed since we received it: %v", service.Namespace, service.Name, err) } glog.Warningf("Failed to persist updated LoadBalancerStatus to service '%s/%s' after creating its load balancer: %v", service.Namespace, service.Name, err) time.Sleep(clientRetryInterval) } return err }
func (rc *RouteController) updateNetworkingCondition(nodeName types.NodeName, routeCreated bool) error { var err error for i := 0; i < updateNodeStatusMaxRetries; i++ { // Patch could also fail, even though the chance is very slim. So we still do // patch in the retry loop. currentTime := metav1.Now() if routeCreated { err = nodeutil.SetNodeCondition(rc.kubeClient, nodeName, v1.NodeCondition{ Type: v1.NodeNetworkUnavailable, Status: v1.ConditionFalse, Reason: "RouteCreated", Message: "RouteController created a route", LastTransitionTime: currentTime, }) } else { err = nodeutil.SetNodeCondition(rc.kubeClient, nodeName, v1.NodeCondition{ Type: v1.NodeNetworkUnavailable, Status: v1.ConditionTrue, Reason: "NoRouteCreated", Message: "RouteController failed to create a route", LastTransitionTime: currentTime, }) } if err == nil { return nil } if i == updateNodeStatusMaxRetries || !errors.IsConflict(err) { glog.Errorf("Error updating node %s: %v", nodeName, err) return err } glog.Errorf("Error updating node %s, retrying: %v", nodeName, err) } return err }
// deletePods will delete all pods from master running on given node, and return true // if any pods were deleted, or were found pending deletion. func deletePods(kubeClient clientset.Interface, recorder record.EventRecorder, nodeName, nodeUID string, daemonStore cache.StoreToDaemonSetLister) (bool, error) { remaining := false selector := fields.OneTermEqualSelector(api.PodHostField, nodeName).String() options := v1.ListOptions{FieldSelector: selector} pods, err := kubeClient.Core().Pods(v1.NamespaceAll).List(options) var updateErrList []error if err != nil { return remaining, err } if len(pods.Items) > 0 { recordNodeEvent(recorder, nodeName, nodeUID, v1.EventTypeNormal, "DeletingAllPods", fmt.Sprintf("Deleting all Pods from Node %v.", nodeName)) } for _, pod := range pods.Items { // Defensive check, also needed for tests. if pod.Spec.NodeName != nodeName { continue } // Set reason and message in the pod object. if _, err = setPodTerminationReason(kubeClient, &pod, nodeName); err != nil { if errors.IsConflict(err) { updateErrList = append(updateErrList, fmt.Errorf("update status failed for pod %q: %v", format.Pod(&pod), err)) continue } } // if the pod has already been marked for deletion, we still return true that there are remaining pods. if pod.DeletionGracePeriodSeconds != nil { remaining = true continue } // if the pod is managed by a daemonset, ignore it _, err := daemonStore.GetPodDaemonSets(&pod) if err == nil { // No error means at least one daemonset was found continue } glog.V(2).Infof("Starting deletion of pod %v", pod.Name) recorder.Eventf(&pod, v1.EventTypeNormal, "NodeControllerEviction", "Marking for deletion Pod %s from Node %s", pod.Name, nodeName) if err := kubeClient.Core().Pods(pod.Namespace).Delete(pod.Name, nil); err != nil { return false, err } remaining = true } if len(updateErrList) > 0 { return false, utilerrors.NewAggregate(updateErrList) } return remaining, nil }
func TestStoreUpdate(t *testing.T) { podA := &api.Pod{ ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test"}, Spec: api.PodSpec{NodeName: "machine"}, } podB := &api.Pod{ ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test"}, Spec: api.PodSpec{NodeName: "machine2"}, } podAWithResourceVersion := &api.Pod{ ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "7"}, Spec: api.PodSpec{NodeName: "machine"}, } testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") destroyFunc, registry := NewTestGenericStoreRegistry(t) defer destroyFunc() // Test1 try to update a non-existing node _, _, err := registry.Update(testContext, podA.Name, rest.DefaultUpdatedObjectInfo(podA, api.Scheme)) if !errors.IsNotFound(err) { t.Errorf("Unexpected error: %v", err) } // Test2 createIfNotFound and verify registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = true if !updateAndVerify(t, testContext, registry, podA) { t.Errorf("Unexpected error updating podA") } registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = false // Test3 outofDate _, _, err = registry.Update(testContext, podAWithResourceVersion.Name, rest.DefaultUpdatedObjectInfo(podAWithResourceVersion, api.Scheme)) if !errors.IsConflict(err) { t.Errorf("Unexpected error updating podAWithResourceVersion: %v", err) } // Test4 normal update and verify if !updateAndVerify(t, testContext, registry, podB) { t.Errorf("Unexpected error updating podB") } // Test5 unconditional update // NOTE: The logic for unconditional updates doesn't make sense to me, and imho should be removed. // doUnconditionalUpdate := resourceVersion == 0 && e.UpdateStrategy.AllowUnconditionalUpdate() // ^^ That condition can *never be true due to the creation of root objects. // // registry.UpdateStrategy.(*testRESTStrategy).allowUnconditionalUpdate = true // updateAndVerify(t, testContext, registry, podAWithResourceVersion) }
func (e *TokensController) deleteToken(ns, name string, uid types.UID) ( /*retry*/ bool, error) { var opts *v1.DeleteOptions if len(uid) > 0 { opts = &v1.DeleteOptions{Preconditions: &v1.Preconditions{UID: &uid}} } err := e.client.Core().Secrets(ns).Delete(name, opts) // NotFound doesn't need a retry (it's already been deleted) // Conflict doesn't need a retry (the UID precondition failed) if err == nil || apierrors.IsNotFound(err) || apierrors.IsConflict(err) { return false, nil } // Retry for any other error return true, err }
func (s *statefulSetTester) update(ns, name string, update func(ss *apps.StatefulSet)) { for i := 0; i < 3; i++ { ss, err := s.c.Apps().StatefulSets(ns).Get(name, metav1.GetOptions{}) if err != nil { framework.Failf("failed to get statefulset %q: %v", name, err) } update(ss) ss, err = s.c.Apps().StatefulSets(ns).Update(ss) if err == nil { return } if !apierrs.IsConflict(err) && !apierrs.IsServerTimeout(err) { framework.Failf("failed to update statefulset %q: %v", name, err) } } framework.Failf("too many retries draining statefulset %q", name) }
func DoPrepareNode(client clientset.Interface, node *v1.Node, strategy PrepareNodeStrategy) error { var err error patch := strategy.PreparePatch(node) if len(patch) == 0 { return nil } for attempt := 0; attempt < retries; attempt++ { if _, err = client.Core().Nodes().Patch(node.Name, types.MergePatchType, []byte(patch)); err == nil { return nil } if !apierrs.IsConflict(err) { return fmt.Errorf("Error while applying patch %v to Node %v: %v", string(patch), node.Name, err) } time.Sleep(100 * time.Millisecond) } return fmt.Errorf("To many conflicts when applying patch %v to Node %v", string(patch), node.Name) }
// UpdateService fetches a service, calls the update function on it, and // then attempts to send the updated service. It tries up to 3 times in the // face of timeouts and conflicts. func (j *ServiceTestJig) UpdateService(namespace, name string, update func(*v1.Service)) (*v1.Service, error) { for i := 0; i < 3; i++ { service, err := j.Client.Core().Services(namespace).Get(name, metav1.GetOptions{}) if err != nil { return nil, fmt.Errorf("Failed to get Service %q: %v", name, err) } update(service) service, err = j.Client.Core().Services(namespace).Update(service) if err == nil { return service, nil } if !errors.IsConflict(err) && !errors.IsServerTimeout(err) { return nil, fmt.Errorf("Failed to update Service %q: %v", name, err) } } return nil, fmt.Errorf("Too many retries updating Service %q", name) }
func (p *patcher) patch(current runtime.Object, modified []byte, source, namespace, name string) ([]byte, error) { var getErr error patchBytes, err := p.patchSimple(current, modified, source, namespace, name) for i := 1; i <= maxPatchRetry && errors.IsConflict(err); i++ { if i > triesBeforeBackOff { p.backOff.Sleep(backOffPeriod) } current, getErr = p.helper.Get(namespace, name, false) if getErr != nil { return nil, getErr } patchBytes, err = p.patchSimple(current, modified, source, namespace, name) } if err != nil && p.force { patchBytes, err = p.deleteAndCreate(modified, namespace, name) } return patchBytes, err }
// RetryConflict executes the provided function repeatedly, retrying if the server returns a conflicting // write. Callers should preserve previous executions if they wish to retry changes. It performs an // exponential backoff. // // var pod *api.Pod // err := RetryOnConflict(DefaultBackoff, func() (err error) { // pod, err = c.Pods("mynamespace").UpdateStatus(podStatus) // return // }) // if err != nil { // // may be conflict if max retries were hit // return err // } // ... // // TODO: Make Backoff an interface? func RetryOnConflict(backoff wait.Backoff, fn func() error) error { var lastConflictErr error err := wait.ExponentialBackoff(backoff, func() (bool, error) { err := fn() switch { case err == nil: return true, nil case errors.IsConflict(err): lastConflictErr = err return false, nil default: return false, err } }) if err == wait.ErrWaitTimeout { err = lastConflictErr } return err }
func (t *Tester) testUpdateWithWrongUID(obj runtime.Object, createFn CreateFunc, getFn GetFunc) { ctx := t.TestContext() foo := copyOrDie(obj) t.setObjectMeta(foo, t.namer(5)) objectMeta := t.getObjectMetaOrFail(foo) objectMeta.UID = types.UID("UID0000") if err := createFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } objectMeta.UID = types.UID("UID1111") obj, created, err := t.storage.(rest.Updater).Update(ctx, objectMeta.Name, rest.DefaultUpdatedObjectInfo(foo, api.Scheme)) if created || obj != nil { t.Errorf("expected nil object and no creation for object: %v", foo) } if err == nil || !errors.IsConflict(err) { t.Errorf("unexpected error: %v", err) } }
// Update updates the pod object. It retries if there is a conflict, throw out error if // there is any other errors. name is the pod name, updateFn is the function updating the // pod object. func (c *PodClient) Update(name string, updateFn func(pod *v1.Pod)) { ExpectNoError(wait.Poll(time.Millisecond*500, time.Second*30, func() (bool, error) { pod, err := c.PodInterface.Get(name, metav1.GetOptions{}) if err != nil { return false, fmt.Errorf("failed to get pod %q: %v", name, err) } updateFn(pod) _, err = c.PodInterface.Update(pod) if err == nil { Logf("Successfully updated pod %q", name) return true, nil } if errors.IsConflict(err) { Logf("Conflicting update to pod %q, re-get and re-update: %v", name, err) return false, nil } return false, fmt.Errorf("failed to update pod %q: %v", name, err) })) }
func (reaper *DeploymentReaper) updateDeploymentWithRetries(namespace, name string, applyUpdate updateDeploymentFunc) (deployment *extensions.Deployment, err error) { deployments := reaper.dClient.Deployments(namespace) err = wait.Poll(10*time.Millisecond, 1*time.Minute, func() (bool, error) { if deployment, err = deployments.Get(name, metav1.GetOptions{}); err != nil { return false, err } // Apply the update, then attempt to push it to the apiserver. applyUpdate(deployment) if deployment, err = deployments.Update(deployment); err == nil { return true, nil } // Retry only on update conflict. if errors.IsConflict(err) { return false, nil } return false, err }) return deployment, err }
// UpdateService fetches a service, calls the update function on it, // and then attempts to send the updated service. It retries up to 2 // times in the face of timeouts and conflicts. func UpdateService(c clientset.Interface, namespace, serviceName string, update func(*v1.Service)) (*v1.Service, error) { var service *v1.Service var err error for i := 0; i < 3; i++ { service, err = c.Core().Services(namespace).Get(serviceName, metav1.GetOptions{}) if err != nil { return service, err } update(service) service, err = c.Core().Services(namespace).Update(service) if !errors.IsConflict(err) && !errors.IsServerTimeout(err) { return service, err } } return service, err }
func (j *testJig) update(update func(ing *extensions.Ingress)) { var err error ns, name := j.ing.Namespace, j.ing.Name for i := 0; i < 3; i++ { j.ing, err = j.client.Extensions().Ingresses(ns).Get(name, metav1.GetOptions{}) if err != nil { framework.Failf("failed to get ingress %q: %v", name, err) } update(j.ing) j.ing, err = j.client.Extensions().Ingresses(ns).Update(j.ing) if err == nil { framework.DescribeIng(j.ing.Namespace) return } if !apierrs.IsConflict(err) && !apierrs.IsServerTimeout(err) { framework.Failf("failed to update ingress %q: %v", name, err) } } framework.Failf("too many retries updating ingress %q", name) }
// ScaleSimple does a simple one-shot attempt at scaling. It returns the // resourceVersion of the statefulset if the update is successful. func (scaler *StatefulSetScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) (string, error) { ps, err := scaler.c.StatefulSets(namespace).Get(name, metav1.GetOptions{}) if err != nil { return "", ScaleError{ScaleGetFailure, "Unknown", err} } if preconditions != nil { if err := preconditions.ValidateStatefulSet(ps); err != nil { return "", err } } ps.Spec.Replicas = int32(newSize) updatedStatefulSet, err := scaler.c.StatefulSets(namespace).Update(ps) if err != nil { if errors.IsConflict(err) { return "", ScaleError{ScaleUpdateConflictFailure, ps.ResourceVersion, err} } return "", ScaleError{ScaleUpdateFailure, ps.ResourceVersion, err} } return updatedStatefulSet.ResourceVersion, nil }
// ScaleSimple does a simple one-shot attempt at scaling. It returns the // resourceVersion of the replication controller if the update is successful. func (scaler *ReplicationControllerScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) (string, error) { controller, err := scaler.c.ReplicationControllers(namespace).Get(name, metav1.GetOptions{}) if err != nil { return "", ScaleError{ScaleGetFailure, "Unknown", err} } if preconditions != nil { if err := preconditions.ValidateReplicationController(controller); err != nil { return "", err } } controller.Spec.Replicas = int32(newSize) updatedRC, err := scaler.c.ReplicationControllers(namespace).Update(controller) if err != nil { if errors.IsConflict(err) { return "", ScaleError{ScaleUpdateConflictFailure, controller.ResourceVersion, err} } return "", ScaleError{ScaleUpdateFailure, controller.ResourceVersion, err} } return updatedRC.ObjectMeta.ResourceVersion, nil }
// retryOnConflictError retries the specified fn if there was a conflict error // it will return an error if the UID for an object changes across retry operations. // TODO RetryOnConflict should be a generic concept in client code func retryOnConflictError(kubeClient clientset.Interface, namespace *v1.Namespace, fn updateNamespaceFunc) (result *v1.Namespace, err error) { latestNamespace := namespace for { result, err = fn(kubeClient, latestNamespace) if err == nil { return result, nil } if !errors.IsConflict(err) { return nil, err } prevNamespace := latestNamespace latestNamespace, err = kubeClient.Core().Namespaces().Get(latestNamespace.Name, metav1.GetOptions{}) if err != nil { return nil, err } if prevNamespace.UID != latestNamespace.UID { return nil, fmt.Errorf("namespace uid has changed across retries") } } }
func DoCleanupNode(client clientset.Interface, nodeName string, strategy PrepareNodeStrategy) error { for attempt := 0; attempt < retries; attempt++ { node, err := client.Core().Nodes().Get(nodeName, metav1.GetOptions{}) if err != nil { return fmt.Errorf("Skipping cleanup of Node: failed to get Node %v: %v", nodeName, err) } updatedNode := strategy.CleanupNode(node) if api.Semantic.DeepEqual(node, updatedNode) { return nil } if _, err = client.Core().Nodes().Update(updatedNode); err == nil { return nil } if !apierrs.IsConflict(err) { return fmt.Errorf("Error when updating Node %v: %v", nodeName, err) } time.Sleep(100 * time.Millisecond) } return fmt.Errorf("To many conflicts when trying to cleanup Node %v", nodeName) }
// updateClaim runs in worker thread and handles "claim added", // "claim updated" and "periodic sync" events. func (ctrl *PersistentVolumeController) updateClaim(claim *v1.PersistentVolumeClaim) { // Store the new claim version in the cache and do not process it if this is // an old version. new, err := ctrl.storeClaimUpdate(claim) if err != nil { glog.Errorf("%v", err) } if !new { return } err = ctrl.syncClaim(claim) if err != nil { if errors.IsConflict(err) { // Version conflict error happens quite often and the controller // recovers from it easily. glog.V(3).Infof("could not sync claim %q: %+v", claimToClaimKey(claim), err) } else { glog.Errorf("could not sync volume %q: %+v", claimToClaimKey(claim), err) } } }