mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	controller: update overlapping deployments to be deletable
This commit is contained in:
		@@ -265,25 +265,6 @@ func (dc *DeploymentController) enqueueDeployment(deployment *extensions.Deploym
 | 
				
			|||||||
	dc.queue.Add(key)
 | 
						dc.queue.Add(key)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (dc *DeploymentController) markDeploymentOverlap(deployment *extensions.Deployment, withDeployment string) (*extensions.Deployment, error) {
 | 
					 | 
				
			||||||
	if deployment.Annotations[util.OverlapAnnotation] == withDeployment {
 | 
					 | 
				
			||||||
		return deployment, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if deployment.Annotations == nil {
 | 
					 | 
				
			||||||
		deployment.Annotations = make(map[string]string)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	deployment.Annotations[util.OverlapAnnotation] = withDeployment
 | 
					 | 
				
			||||||
	return dc.client.Extensions().Deployments(deployment.Namespace).Update(deployment)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (dc *DeploymentController) clearDeploymentOverlap(deployment *extensions.Deployment) (*extensions.Deployment, error) {
 | 
					 | 
				
			||||||
	if len(deployment.Annotations[util.OverlapAnnotation]) == 0 {
 | 
					 | 
				
			||||||
		return deployment, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	delete(deployment.Annotations, util.OverlapAnnotation)
 | 
					 | 
				
			||||||
	return dc.client.Extensions().Deployments(deployment.Namespace).Update(deployment)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// worker runs a worker thread that just dequeues items, processes them, and marks them done.
 | 
					// worker runs a worker thread that just dequeues items, processes them, and marks them done.
 | 
				
			||||||
// It enforces that the syncHandler is never invoked concurrently with the same key.
 | 
					// It enforces that the syncHandler is never invoked concurrently with the same key.
 | 
				
			||||||
func (dc *DeploymentController) worker() {
 | 
					func (dc *DeploymentController) worker() {
 | 
				
			||||||
@@ -342,12 +323,6 @@ func (dc *DeploymentController) syncDeployment(key string) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	deployment := obj.(*extensions.Deployment)
 | 
						deployment := obj.(*extensions.Deployment)
 | 
				
			||||||
	everything := unversioned.LabelSelector{}
 | 
					 | 
				
			||||||
	if reflect.DeepEqual(deployment.Spec.Selector, &everything) {
 | 
					 | 
				
			||||||
		dc.eventRecorder.Eventf(deployment, api.EventTypeWarning, "SelectingAll", "This deployment is selecting all pods. A non-empty selector is required.")
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Deep-copy otherwise we are mutating our cache.
 | 
						// Deep-copy otherwise we are mutating our cache.
 | 
				
			||||||
	// TODO: Deep-copy only when needed.
 | 
						// TODO: Deep-copy only when needed.
 | 
				
			||||||
	d, err := util.DeploymentDeepCopy(deployment)
 | 
						d, err := util.DeploymentDeepCopy(deployment)
 | 
				
			||||||
@@ -355,13 +330,23 @@ func (dc *DeploymentController) syncDeployment(key string) error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						everything := unversioned.LabelSelector{}
 | 
				
			||||||
 | 
						if reflect.DeepEqual(d.Spec.Selector, &everything) {
 | 
				
			||||||
 | 
							dc.eventRecorder.Eventf(d, api.EventTypeWarning, "SelectingAll", "This deployment is selecting all pods. A non-empty selector is required.")
 | 
				
			||||||
 | 
							if d.Status.ObservedGeneration < d.Generation {
 | 
				
			||||||
 | 
								d.Status.ObservedGeneration = d.Generation
 | 
				
			||||||
 | 
								dc.client.Extensions().Deployments(d.Namespace).UpdateStatus(d)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if d.DeletionTimestamp != nil {
 | 
						if d.DeletionTimestamp != nil {
 | 
				
			||||||
		return dc.syncStatusOnly(d)
 | 
							return dc.syncStatusOnly(d)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Handle overlapping deployments by deterministically avoid syncing deployments that fight over ReplicaSets.
 | 
						// Handle overlapping deployments by deterministically avoid syncing deployments that fight over ReplicaSets.
 | 
				
			||||||
	if err = dc.handleOverlap(d); err != nil {
 | 
						if err = dc.handleOverlap(d); err != nil {
 | 
				
			||||||
		dc.eventRecorder.Eventf(deployment, api.EventTypeWarning, "SelectorOverlap", err.Error())
 | 
							dc.eventRecorder.Eventf(d, api.EventTypeWarning, "SelectorOverlap", err.Error())
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -413,17 +398,15 @@ func (dc *DeploymentController) handleOverlap(d *extensions.Deployment) error {
 | 
				
			|||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			overlapping = true
 | 
								overlapping = true
 | 
				
			||||||
			// We don't care if the overlapping annotation update failed or not (we don't make decision on it)
 | 
								// Skip syncing this one if older overlapping one is found.
 | 
				
			||||||
			d, _ = dc.markDeploymentOverlap(d, other.Name)
 | 
					 | 
				
			||||||
			deploymentCopy, _ = dc.markDeploymentOverlap(deploymentCopy, d.Name)
 | 
					 | 
				
			||||||
			// Skip syncing this one if older overlapping one is found
 | 
					 | 
				
			||||||
			// TODO: figure out a better way to determine which deployment to skip,
 | 
					 | 
				
			||||||
			// either with controller reference, or with validation.
 | 
					 | 
				
			||||||
			// Using oldest active replica set to determine which deployment to skip wouldn't make much difference,
 | 
					 | 
				
			||||||
			// since new replica set hasn't been created after selector update
 | 
					 | 
				
			||||||
			if util.SelectorUpdatedBefore(deploymentCopy, d) {
 | 
								if util.SelectorUpdatedBefore(deploymentCopy, d) {
 | 
				
			||||||
				return fmt.Errorf("found deployment %s/%s has overlapping selector with an older deployment %s/%s, skip syncing it", d.Namespace, d.Name, other.Namespace, other.Name)
 | 
									// We don't care if the overlapping annotation update failed or not (we don't make decision on it)
 | 
				
			||||||
 | 
									dc.markDeploymentOverlap(d, deploymentCopy.Name)
 | 
				
			||||||
 | 
									dc.clearDeploymentOverlap(deploymentCopy)
 | 
				
			||||||
 | 
									return fmt.Errorf("found deployment %s/%s has overlapping selector with an older deployment %s/%s, skip syncing it", d.Namespace, d.Name, deploymentCopy.Namespace, deploymentCopy.Name)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								dc.markDeploymentOverlap(deploymentCopy, d.Name)
 | 
				
			||||||
 | 
								d, _ = dc.clearDeploymentOverlap(d)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !overlapping {
 | 
						if !overlapping {
 | 
				
			||||||
@@ -432,3 +415,24 @@ func (dc *DeploymentController) handleOverlap(d *extensions.Deployment) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (dc *DeploymentController) markDeploymentOverlap(deployment *extensions.Deployment, withDeployment string) (*extensions.Deployment, error) {
 | 
				
			||||||
 | 
						if deployment.Annotations[util.OverlapAnnotation] == withDeployment && deployment.Status.ObservedGeneration >= deployment.Generation {
 | 
				
			||||||
 | 
							return deployment, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if deployment.Annotations == nil {
 | 
				
			||||||
 | 
							deployment.Annotations = make(map[string]string)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Update observedGeneration for overlapping deployments so that their deletion won't be blocked.
 | 
				
			||||||
 | 
						deployment.Status.ObservedGeneration = deployment.Generation
 | 
				
			||||||
 | 
						deployment.Annotations[util.OverlapAnnotation] = withDeployment
 | 
				
			||||||
 | 
						return dc.client.Extensions().Deployments(deployment.Namespace).UpdateStatus(deployment)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (dc *DeploymentController) clearDeploymentOverlap(deployment *extensions.Deployment) (*extensions.Deployment, error) {
 | 
				
			||||||
 | 
						if len(deployment.Annotations[util.OverlapAnnotation]) == 0 {
 | 
				
			||||||
 | 
							return deployment, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						delete(deployment.Annotations, util.OverlapAnnotation)
 | 
				
			||||||
 | 
						return dc.client.Extensions().Deployments(deployment.Namespace).UpdateStatus(deployment)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user