Rollback a Deployment

PHOTO EMBED

Sun Mar 28 2021 07:25:33 GMT+0000 (Coordinated Universal Time)

Saved by @littlepoint #go #kubernetes #kubectl

func (r *DeploymentRollbacker) Rollback(obj runtime.Object, updatedAnnotations map[string]string, toRevision int64, dryRunStrategy cmdutil.DryRunStrategy) (string, error) {
	if toRevision < 0 {
		return "", revisionNotFoundErr(toRevision)
	}
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return "", fmt.Errorf("failed to create accessor for kind %v: %s", obj.GetObjectKind(), err.Error())
	}
	name := accessor.GetName()
	namespace := accessor.GetNamespace()

	// TODO: Fix this after kubectl has been removed from core. It is not possible to convert the runtime.Object
	// to the external appsv1 Deployment without round-tripping through an internal version of Deployment. We're
	// currently getting rid of all internal versions of resources. So we specifically request the appsv1 version
	// here. This follows the same pattern as for DaemonSet and StatefulSet.
	deployment, err := r.c.AppsV1().Deployments(namespace).Get(context.TODO(), name, metav1.GetOptions{})
	if err != nil {
		return "", fmt.Errorf("failed to retrieve Deployment %s: %v", name, err)
	}

	rsForRevision, err := deploymentRevision(deployment, r.c, toRevision)
	if err != nil {
		return "", err
	}
	if dryRunStrategy == cmdutil.DryRunClient {
		return printTemplate(&rsForRevision.Spec.Template)
	}
	if deployment.Spec.Paused {
		return "", fmt.Errorf("you cannot rollback a paused deployment; resume it first with 'kubectl rollout resume deployment/%s' and try again", name)
	}

	// Skip if the revision already matches current Deployment
	if equalIgnoreHash(&rsForRevision.Spec.Template, &deployment.Spec.Template) {
		return fmt.Sprintf("%s (current template already matches revision %d)", rollbackSkipped, toRevision), nil
	}

	// remove hash label before patching back into the deployment
	delete(rsForRevision.Spec.Template.Labels, appsv1.DefaultDeploymentUniqueLabelKey)

	// compute deployment annotations
	annotations := map[string]string{}
	for k := range annotationsToSkip {
		if v, ok := deployment.Annotations[k]; ok {
			annotations[k] = v
		}
	}
	for k, v := range rsForRevision.Annotations {
		if !annotationsToSkip[k] {
			annotations[k] = v
		}
	}

	// make patch to restore
	patchType, patch, err := getDeploymentPatch(&rsForRevision.Spec.Template, annotations)
	if err != nil {
		return "", fmt.Errorf("failed restoring revision %d: %v", toRevision, err)
	}

	patchOptions := metav1.PatchOptions{}
	if dryRunStrategy == cmdutil.DryRunServer {
		patchOptions.DryRun = []string{metav1.DryRunAll}
	}
	// Restore revision
	if _, err = r.c.AppsV1().Deployments(namespace).Patch(context.TODO(), name, patchType, patch, patchOptions); err != nil {
		return "", fmt.Errorf("failed restoring revision %d: %v", toRevision, err)
	}
	return rollbackSuccess, nil
}
content_copyCOPY