github.com/koderover/helm@v2.17.0+incompatible/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 targetRelease := &release.Release{ 98 Name: req.Name, 99 Namespace: currentRelease.Namespace, 100 Chart: previousRelease.Chart, 101 Config: previousRelease.Config, 102 Info: &release.Info{ 103 FirstDeployed: currentRelease.Info.FirstDeployed, 104 LastDeployed: timeconv.Now(), 105 Status: &release.Status{ 106 Code: release.Status_PENDING_ROLLBACK, 107 Notes: previousRelease.Info.Status.Notes, 108 }, 109 // Because we lose the reference to previous version elsewhere, we set the 110 // message here, and only override it later if we experience failure. 111 Description: description, 112 }, 113 Version: currentRelease.Version + 1, 114 Manifest: previousRelease.Manifest, 115 Hooks: previousRelease.Hooks, 116 } 117 118 return currentRelease, targetRelease, nil 119 } 120 121 func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.Release, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) { 122 res := &services.RollbackReleaseResponse{Release: targetRelease} 123 124 if req.DryRun { 125 s.Log("dry run for %s", targetRelease.Name) 126 return res, nil 127 } 128 129 // pre-rollback hooks 130 if !req.DisableHooks { 131 if err := s.execHook(targetRelease.Hooks, targetRelease.Name, targetRelease.Namespace, hooks.PreRollback, req.Timeout); err != nil { 132 return res, err 133 } 134 } else { 135 s.Log("rollback hooks disabled for %s", req.Name) 136 } 137 138 if err := s.ReleaseModule.Rollback(currentRelease, targetRelease, req, s.env); err != nil { 139 msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err) 140 s.Log("warning: %s", msg) 141 currentRelease.Info.Status.Code = release.Status_SUPERSEDED 142 targetRelease.Info.Status.Code = release.Status_FAILED 143 targetRelease.Info.Description = msg 144 s.recordRelease(currentRelease, true) 145 s.recordRelease(targetRelease, true) 146 return res, err 147 } 148 149 // post-rollback hooks 150 if !req.DisableHooks { 151 if err := s.execHook(targetRelease.Hooks, targetRelease.Name, targetRelease.Namespace, hooks.PostRollback, req.Timeout); err != nil { 152 return res, err 153 } 154 } 155 156 // update the current release 157 s.Log("superseding previous deployment %d", currentRelease.Version) 158 currentRelease.Info.Status.Code = release.Status_SUPERSEDED 159 s.recordRelease(currentRelease, true) 160 161 // Supersede all previous deployments, see issue #2941. 162 deployed, err := s.env.Releases.DeployedAll(currentRelease.Name) 163 if err != nil && !strings.Contains(err.Error(), storage.NoReleasesErr) { 164 return nil, err 165 } 166 for _, r := range deployed { 167 s.Log("superseding previous deployment %d", r.Version) 168 r.Info.Status.Code = release.Status_SUPERSEDED 169 s.recordRelease(r, true) 170 } 171 172 targetRelease.Info.Status.Code = release.Status_DEPLOYED 173 174 return res, nil 175 }