github.com/wangchanggan/helm@v0.0.0-20211020154240-11b1b7d5406d/pkg/tiller/release_rollback.go (about)

     1  /*
     2  Copyright The Helm Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package tiller
    18  
    19  import (
    20  	"fmt"
    21  	"k8s.io/helm/pkg/storage"
    22  	"strings"
    23  
    24  	ctx "golang.org/x/net/context"
    25  
    26  	"k8s.io/helm/pkg/hooks"
    27  	"k8s.io/helm/pkg/proto/hapi/release"
    28  	"k8s.io/helm/pkg/proto/hapi/services"
    29  	"k8s.io/helm/pkg/timeconv"
    30  )
    31  
    32  // RollbackRelease rolls back to a previous version of the given release.
    33  func (s *ReleaseServer) RollbackRelease(c ctx.Context, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) {
    34  	s.Log("preparing rollback of %s", req.Name)
    35  	currentRelease, targetRelease, err := s.prepareRollback(req)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  
    40  	if !req.DryRun {
    41  		s.Log("creating rolled back release for %s", req.Name)
    42  		if err := s.env.Releases.Create(targetRelease); err != nil {
    43  			return nil, err
    44  		}
    45  	}
    46  	s.Log("performing rollback of %s", req.Name)
    47  	res, err := s.performRollback(currentRelease, targetRelease, req)
    48  	if err != nil {
    49  		return res, err
    50  	}
    51  
    52  	if !req.DryRun {
    53  		s.Log("updating status for rolled back release for %s", req.Name)
    54  		if err := s.env.Releases.Update(targetRelease); err != nil {
    55  			return res, err
    56  		}
    57  	}
    58  
    59  	return res, nil
    60  }
    61  
    62  // prepareRollback finds the previous release and prepares a new release object with
    63  // the previous release's configuration
    64  func (s *ReleaseServer) prepareRollback(req *services.RollbackReleaseRequest) (*release.Release, *release.Release, error) {
    65  	if err := validateReleaseName(req.Name); err != nil {
    66  		s.Log("prepareRollback: Release name is invalid: %s", req.Name)
    67  		return nil, nil, err
    68  	}
    69  
    70  	if req.Version < 0 {
    71  		return nil, nil, errInvalidRevision
    72  	}
    73  
    74  	currentRelease, err := s.env.Releases.Last(req.Name)
    75  	if err != nil {
    76  		return nil, nil, err
    77  	}
    78  
    79  	previousVersion := req.Version
    80  	if req.Version == 0 {
    81  		previousVersion = currentRelease.Version - 1
    82  	}
    83  
    84  	s.Log("rolling back %s (current: v%d, target: v%d)", req.Name, currentRelease.Version, previousVersion)
    85  
    86  	previousRelease, err := s.env.Releases.Get(req.Name, previousVersion)
    87  	if err != nil {
    88  		return nil, nil, err
    89  	}
    90  
    91  	description := req.Description
    92  	if req.Description == "" {
    93  		description = fmt.Sprintf("Rollback to %d", previousVersion)
    94  	}
    95  
    96  	// Store a new release object with previous release's configuration
    97  	// 重新定义一个具有前一个Release配置的新Release
    98  	targetRelease := &release.Release{
    99  		Name:      req.Name,
   100  		Namespace: currentRelease.Namespace,
   101  		Chart:     previousRelease.Chart,
   102  		Config:    previousRelease.Config,
   103  		Info: &release.Info{
   104  			FirstDeployed: currentRelease.Info.FirstDeployed,
   105  			LastDeployed:  timeconv.Now(),
   106  			Status: &release.Status{
   107  				Code:  release.Status_PENDING_ROLLBACK,
   108  				Notes: previousRelease.Info.Status.Notes,
   109  			},
   110  			// Because we lose the reference to previous version elsewhere, we set the
   111  			// message here, and only override it later if we experience failure.
   112  			// 因为在其他地方丢失了对以前版本的引用,所以在这里设置了消息,只有在遇到失败时才会覆盖它
   113  			Description: description,
   114  		},
   115  		Version:  currentRelease.Version + 1,
   116  		Manifest: previousRelease.Manifest,
   117  		Hooks:    previousRelease.Hooks,
   118  	}
   119  
   120  	return currentRelease, targetRelease, nil
   121  }
   122  
   123  func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.Release, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) {
   124  	res := &services.RollbackReleaseResponse{Release: targetRelease}
   125  
   126  	if req.DryRun {
   127  		s.Log("dry run for %s", targetRelease.Name)
   128  		return res, nil
   129  	}
   130  
   131  	// pre-rollback hooks
   132  	if !req.DisableHooks {
   133  		if err := s.execHook(targetRelease.Hooks, targetRelease.Name, targetRelease.Namespace, hooks.PreRollback, req.Timeout); err != nil {
   134  			return res, err
   135  		}
   136  	} else {
   137  		s.Log("rollback hooks disabled for %s", req.Name)
   138  	}
   139  
   140  	if err := s.ReleaseModule.Rollback(currentRelease, targetRelease, req, s.env); err != nil {
   141  		msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err)
   142  		s.Log("warning: %s", msg)
   143  		currentRelease.Info.Status.Code = release.Status_SUPERSEDED
   144  		targetRelease.Info.Status.Code = release.Status_FAILED
   145  		targetRelease.Info.Description = msg
   146  		s.recordRelease(currentRelease, true)
   147  		s.recordRelease(targetRelease, true)
   148  		return res, err
   149  	}
   150  
   151  	// post-rollback hooks
   152  	if !req.DisableHooks {
   153  		if err := s.execHook(targetRelease.Hooks, targetRelease.Name, targetRelease.Namespace, hooks.PostRollback, req.Timeout); err != nil {
   154  			return res, err
   155  		}
   156  	}
   157  
   158  	// update the current release
   159  	s.Log("superseding previous deployment %d", currentRelease.Version)
   160  	currentRelease.Info.Status.Code = release.Status_SUPERSEDED
   161  	s.recordRelease(currentRelease, true)
   162  
   163  	// Supersede all previous deployments, see issue #2941.
   164  	deployed, err := s.env.Releases.DeployedAll(currentRelease.Name)
   165  	if err != nil && !strings.Contains(err.Error(), storage.NoReleasesErr) {
   166  		return nil, err
   167  	}
   168  	for _, r := range deployed {
   169  		s.Log("superseding previous deployment %d", r.Version)
   170  		r.Info.Status.Code = release.Status_SUPERSEDED
   171  		s.recordRelease(r, true)
   172  	}
   173  
   174  	targetRelease.Info.Status.Code = release.Status_DEPLOYED
   175  
   176  	return res, nil
   177  }