func verifyDeployment(fedDeployment, localDeployment *v1beta1.Deployment) bool { localDeployment = fedutil.DeepCopyDeployment(localDeployment) localDeployment.Spec.Replicas = fedDeployment.Spec.Replicas return fedutil.DeploymentEquivalent(fedDeployment, localDeployment) }
func (fdc *DeploymentController) reconcileDeployment(key string) (reconciliationStatus, error) { if !fdc.isSynced() { return statusNotSynced, nil } glog.V(4).Infof("Start reconcile deployment %q", key) startTime := time.Now() defer glog.V(4).Infof("Finished reconcile deployment %q (%v)", key, time.Now().Sub(startTime)) objFromStore, exists, err := fdc.deploymentStore.GetByKey(key) if err != nil { return statusError, err } if !exists { // don't delete local deployments for now. Do not reconcile it anymore. return statusAllOk, nil } obj, err := api.Scheme.DeepCopy(objFromStore) fd, ok := obj.(*extensionsv1.Deployment) if err != nil || !ok { glog.Errorf("Error in retrieving obj from store: %v, %v", ok, err) return statusError, err } if fd.DeletionTimestamp != nil { if err := fdc.delete(fd); err != nil { glog.Errorf("Failed to delete %s: %v", fd.Name, err) fdc.eventRecorder.Eventf(fd, api.EventTypeNormal, "DeleteFailed", "Deployment delete failed: %v", err) return statusError, err } return statusAllOk, nil } glog.V(3).Infof("Ensuring delete object from underlying clusters finalizer for deployment: %s", fd.Name) // Add the required finalizers before creating a deployment in underlying clusters. updatedDeploymentObj, err := fdc.deletionHelper.EnsureFinalizers(fd) if err != nil { glog.Errorf("Failed to ensure delete object from underlying clusters finalizer in deployment %s: %v", fd.Name, err) return statusError, err } fd = updatedDeploymentObj.(*extensionsv1.Deployment) glog.V(3).Infof("Syncing deployment %s in underlying clusters", fd.Name) clusters, err := fdc.fedDeploymentInformer.GetReadyClusters() if err != nil { return statusError, err } // collect current status and do schedule allPods, err := fdc.fedPodInformer.GetTargetStore().List() if err != nil { return statusError, err } podStatus, err := podanalyzer.AnalysePods(fd.Spec.Selector, allPods, time.Now()) current := make(map[string]int64) estimatedCapacity := make(map[string]int64) for _, cluster := range clusters { ldObj, exists, err := fdc.fedDeploymentInformer.GetTargetStore().GetByKey(cluster.Name, key) if err != nil { return statusError, err } if exists { ld := ldObj.(*extensionsv1.Deployment) current[cluster.Name] = int64(podStatus[cluster.Name].RunningAndReady) // include pending as well? unschedulable := int64(podStatus[cluster.Name].Unschedulable) if unschedulable > 0 { estimatedCapacity[cluster.Name] = int64(*ld.Spec.Replicas) - unschedulable } } } scheduleResult := fdc.schedule(fd, clusters, current, estimatedCapacity) glog.V(4).Infof("Start syncing local deployment %s: %v", key, scheduleResult) fedStatus := extensionsv1.DeploymentStatus{ObservedGeneration: fd.Generation} operations := make([]fedutil.FederatedOperation, 0) for clusterName, replicas := range scheduleResult { ldObj, exists, err := fdc.fedDeploymentInformer.GetTargetStore().GetByKey(clusterName, key) if err != nil { return statusError, err } // The object can be modified. ld := fedutil.DeepCopyDeployment(fd) specReplicas := int32(replicas) ld.Spec.Replicas = &specReplicas if !exists { if replicas > 0 { fdc.eventRecorder.Eventf(fd, api.EventTypeNormal, "CreateInCluster", "Creating deployment in cluster %s", clusterName) operations = append(operations, fedutil.FederatedOperation{ Type: fedutil.OperationTypeAdd, Obj: ld, ClusterName: clusterName, }) } } else { // TODO: Update only one deployment at a time if update strategy is rolling udpate. currentLd := ldObj.(*extensionsv1.Deployment) // Update existing replica set, if needed. if !fedutil.DeploymentEquivalent(ld, currentLd) { fdc.eventRecorder.Eventf(fd, api.EventTypeNormal, "UpdateInCluster", "Updating deployment in cluster %s", clusterName) operations = append(operations, fedutil.FederatedOperation{ Type: fedutil.OperationTypeUpdate, Obj: ld, ClusterName: clusterName, }) glog.Infof("Updating %s in %s", currentLd.Name, clusterName) } fedStatus.Replicas += currentLd.Status.Replicas fedStatus.AvailableReplicas += currentLd.Status.AvailableReplicas fedStatus.UnavailableReplicas += currentLd.Status.UnavailableReplicas } } if fedStatus.Replicas != fd.Status.Replicas || fedStatus.AvailableReplicas != fd.Status.AvailableReplicas || fedStatus.UnavailableReplicas != fd.Status.UnavailableReplicas { fd.Status = fedStatus _, err = fdc.fedClient.Extensions().Deployments(fd.Namespace).UpdateStatus(fd) if err != nil { return statusError, err } } if len(operations) == 0 { // Everything is in order return statusAllOk, nil } err = fdc.fedUpdater.UpdateWithOnError(operations, updateTimeout, func(op fedutil.FederatedOperation, operror error) { fdc.eventRecorder.Eventf(fd, api.EventTypeNormal, "FailedUpdateInCluster", "Deployment update in cluster %s failed: %v", op.ClusterName, operror) }) if err != nil { glog.Errorf("Failed to execute updates for %s: %v", key, err) return statusError, err } // Some operations were made, reconcile after a while. return statusNeedRecheck, nil }