// History returns a revision-to-replicaset map as the revision history of a deployment func (h *DeploymentHistoryViewer) History(namespace, name string) (HistoryInfo, error) { historyInfo := HistoryInfo{ RevisionToTemplate: make(map[int64]*api.PodTemplateSpec), } deployment, err := h.c.Extensions().Deployments(namespace).Get(name) if err != nil { return historyInfo, fmt.Errorf("failed to retrieve deployment %s: %v", name, err) } _, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(deployment, h.c) if err != nil { return historyInfo, fmt.Errorf("failed to retrieve replica sets from deployment %s: %v", name, err) } allRSs := allOldRSs if newRS != nil { allRSs = append(allRSs, newRS) } for _, rs := range allRSs { v, err := deploymentutil.Revision(rs) if err != nil { continue } historyInfo.RevisionToTemplate[v] = &rs.Spec.Template changeCause := getChangeCause(rs) if historyInfo.RevisionToTemplate[v].Annotations == nil { historyInfo.RevisionToTemplate[v].Annotations = make(map[string]string) } if len(changeCause) > 0 { historyInfo.RevisionToTemplate[v].Annotations[ChangeCauseAnnotation] = changeCause } } return historyInfo, nil }
func testDeploymentLabelAdopted(f *framework.Framework) { ns := f.Namespace.Name // TODO: remove unversionedClient when the refactoring is done. Currently some // functions like verifyPod still expects a unversioned#Client. unversionedClient := f.Client c := adapter.FromUnversionedClient(unversionedClient) // Create nginx pods. podName := "nginx" podLabels := map[string]string{"name": podName} rsName := "test-adopted-controller" replicas := int32(3) image := nginxImage _, err := c.Extensions().ReplicaSets(ns).Create(newRS(rsName, replicas, podLabels, podName, image)) Expect(err).NotTo(HaveOccurred()) // Verify that the required pods have come up. err = framework.VerifyPods(unversionedClient, ns, podName, false, 3) if err != nil { framework.Logf("error in waiting for pods to come up: %s", err) Expect(err).NotTo(HaveOccurred()) } // Create a nginx deployment to adopt the old rs. deploymentName := "test-adopted-deployment" framework.Logf("Creating deployment %s", deploymentName) _, err = c.Extensions().Deployments(ns).Create(newDeployment(deploymentName, replicas, podLabels, podName, image, extensions.RollingUpdateDeploymentStrategyType, nil)) Expect(err).NotTo(HaveOccurred()) defer stopDeployment(c, f.Client, ns, deploymentName) // Wait for it to be updated to revision 1 err = framework.WaitForDeploymentRevisionAndImage(c, ns, deploymentName, "1", image) Expect(err).NotTo(HaveOccurred()) // The RS and pods should be relabeled before the status is updated by syncRollingUpdateDeployment err = framework.WaitForDeploymentStatus(c, ns, deploymentName, replicas, replicas-1, replicas+1, 0) Expect(err).NotTo(HaveOccurred()) // There should be no old RSs (overlapping RS) deployment, err := c.Extensions().Deployments(ns).Get(deploymentName) Expect(err).NotTo(HaveOccurred()) oldRSs, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(deployment, c) Expect(err).NotTo(HaveOccurred()) Expect(len(oldRSs)).Should(Equal(0)) Expect(len(allOldRSs)).Should(Equal(0)) // New RS should contain pod-template-hash in its selector, label, and template label err = framework.CheckRSHashLabel(newRS) Expect(err).NotTo(HaveOccurred()) // All pods targeted by the deployment should contain pod-template-hash in their labels, and there should be only 3 pods selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector) Expect(err).NotTo(HaveOccurred()) options := api.ListOptions{LabelSelector: selector} pods, err := c.Core().Pods(ns).List(options) Expect(err).NotTo(HaveOccurred()) err = framework.CheckPodHashLabel(pods) Expect(err).NotTo(HaveOccurred()) Expect(int32(len(pods.Items))).Should(Equal(replicas)) }
// ViewHistory prints the revision history of a deployment func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision int64) (string, error) { deployment, err := h.c.Extensions().Deployments(namespace).Get(name) if err != nil { return "", fmt.Errorf("failed to retrieve deployment %s: %v", name, err) } _, allOldRSs, newRS, err := deploymentutil.GetAllReplicaSets(deployment, h.c) if err != nil { return "", fmt.Errorf("failed to retrieve old replica sets from deployment %s: %v", name, err) } historyInfo := make(map[int64]*api.PodTemplateSpec) allRSs := allOldRSs if newRS != nil { allRSs = append(allRSs, newRS) } for _, rs := range allRSs { v, err := deploymentutil.Revision(rs) if err != nil { continue } historyInfo[v] = &rs.Spec.Template changeCause := getChangeCause(rs) if historyInfo[v].Annotations == nil { historyInfo[v].Annotations = make(map[string]string) } if len(changeCause) > 0 { historyInfo[v].Annotations[ChangeCauseAnnotation] = changeCause } } if len(historyInfo) == 0 { return "No rollout history found.", nil } if revision > 0 { // Print details of a specific revision template, ok := historyInfo[revision] if !ok { return "", fmt.Errorf("unable to find the specified revision") } buf := bytes.NewBuffer([]byte{}) DescribePodTemplate(template, buf) return buf.String(), nil } // Sort the revisionToChangeCause map by revision var revisions []int64 for r := range historyInfo { revisions = append(revisions, r) } sliceutil.SortInts64(revisions) return tabbedString(func(out io.Writer) error { fmt.Fprintf(out, "REVISION\tCHANGE-CAUSE\n") for _, r := range revisions { // Find the change-cause of revision r changeCause := historyInfo[r].Annotations[ChangeCauseAnnotation] if len(changeCause) == 0 { changeCause = "<none>" } fmt.Fprintf(out, "%d\t%s\n", r, changeCause) } return nil }) }