github.com/zoumo/helm@v2.5.0+incompatible/pkg/tiller/release_rollback.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors All rights reserved. 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 22 ctx "golang.org/x/net/context" 23 24 "k8s.io/helm/pkg/hooks" 25 "k8s.io/helm/pkg/proto/hapi/release" 26 "k8s.io/helm/pkg/proto/hapi/services" 27 "k8s.io/helm/pkg/timeconv" 28 ) 29 30 // RollbackRelease rolls back to a previous version of the given release. 31 func (s *ReleaseServer) RollbackRelease(c ctx.Context, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) { 32 err := s.env.Releases.LockRelease(req.Name) 33 if err != nil { 34 return nil, err 35 } 36 defer s.env.Releases.UnlockRelease(req.Name) 37 38 s.Log("preparing rollback of %s", req.Name) 39 currentRelease, targetRelease, err := s.prepareRollback(req) 40 if err != nil { 41 return nil, err 42 } 43 44 s.Log("performing rollback of %s", req.Name) 45 res, err := s.performRollback(currentRelease, targetRelease, req) 46 if err != nil { 47 return res, err 48 } 49 50 if !req.DryRun { 51 s.Log("creating rolled back release %s", req.Name) 52 if err := s.env.Releases.Create(targetRelease); err != nil { 53 return res, err 54 } 55 } 56 57 return res, nil 58 } 59 60 // prepareRollback finds the previous release and prepares a new release object with 61 // the previous release's configuration 62 func (s *ReleaseServer) prepareRollback(req *services.RollbackReleaseRequest) (*release.Release, *release.Release, error) { 63 switch { 64 case !ValidName.MatchString(req.Name): 65 return nil, nil, errMissingRelease 66 case req.Version < 0: 67 return nil, nil, errInvalidRevision 68 } 69 70 crls, err := s.env.Releases.Last(req.Name) 71 if err != nil { 72 return nil, nil, err 73 } 74 75 rbv := req.Version 76 if req.Version == 0 { 77 rbv = crls.Version - 1 78 } 79 80 s.Log("rolling back %s (current: v%d, target: v%d)", req.Name, crls.Version, rbv) 81 82 prls, err := s.env.Releases.Get(req.Name, rbv) 83 if err != nil { 84 return nil, nil, err 85 } 86 87 // Store a new release object with previous release's configuration 88 target := &release.Release{ 89 Name: req.Name, 90 Namespace: crls.Namespace, 91 Chart: prls.Chart, 92 Config: prls.Config, 93 Info: &release.Info{ 94 FirstDeployed: crls.Info.FirstDeployed, 95 LastDeployed: timeconv.Now(), 96 Status: &release.Status{ 97 Code: release.Status_UNKNOWN, 98 Notes: prls.Info.Status.Notes, 99 }, 100 // Because we lose the reference to rbv elsewhere, we set the 101 // message here, and only override it later if we experience failure. 102 Description: fmt.Sprintf("Rollback to %d", rbv), 103 }, 104 Version: crls.Version + 1, 105 Manifest: prls.Manifest, 106 Hooks: prls.Hooks, 107 Annotations: prls.Annotations, 108 } 109 110 return crls, target, nil 111 } 112 113 func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.Release, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) { 114 res := &services.RollbackReleaseResponse{Release: targetRelease} 115 116 if req.DryRun { 117 s.Log("dry run for %s", targetRelease.Name) 118 return res, nil 119 } 120 121 // pre-rollback hooks 122 if !req.DisableHooks { 123 if err := s.execHook(targetRelease.Hooks, targetRelease.Name, targetRelease.Namespace, hooks.PreRollback, req.Timeout); err != nil { 124 return res, err 125 } 126 } else { 127 s.Log("rollback hooks disabled for %s", req.Name) 128 } 129 130 if err := s.ReleaseModule.Rollback(currentRelease, targetRelease, req, s.env); err != nil { 131 msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err) 132 s.Log("warning: %s", msg) 133 currentRelease.Info.Status.Code = release.Status_SUPERSEDED 134 targetRelease.Info.Status.Code = release.Status_FAILED 135 targetRelease.Info.Description = msg 136 s.recordRelease(currentRelease, true) 137 s.recordRelease(targetRelease, false) 138 return res, err 139 } 140 141 // post-rollback hooks 142 if !req.DisableHooks { 143 if err := s.execHook(targetRelease.Hooks, targetRelease.Name, targetRelease.Namespace, hooks.PostRollback, req.Timeout); err != nil { 144 return res, err 145 } 146 } 147 148 currentRelease.Info.Status.Code = release.Status_SUPERSEDED 149 s.recordRelease(currentRelease, true) 150 151 targetRelease.Info.Status.Code = release.Status_DEPLOYED 152 153 return res, nil 154 }