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 }