github.com/zoumo/helm@v2.5.0+incompatible/pkg/tiller/release_update.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/chartutil" 25 "k8s.io/helm/pkg/hooks" 26 "k8s.io/helm/pkg/proto/hapi/release" 27 "k8s.io/helm/pkg/proto/hapi/services" 28 "k8s.io/helm/pkg/timeconv" 29 ) 30 31 // UpdateRelease takes an existing release and new information, and upgrades the release. 32 func (s *ReleaseServer) UpdateRelease(c ctx.Context, req *services.UpdateReleaseRequest) (*services.UpdateReleaseResponse, error) { 33 err := s.env.Releases.LockRelease(req.Name) 34 if err != nil { 35 return nil, err 36 } 37 defer s.env.Releases.UnlockRelease(req.Name) 38 39 s.Log("preparing update for %s", req.Name) 40 currentRelease, updatedRelease, err := s.prepareUpdate(req) 41 if err != nil { 42 return nil, err 43 } 44 45 s.Log("performing update for %s", req.Name) 46 res, err := s.performUpdate(currentRelease, updatedRelease, req) 47 if err != nil { 48 return res, err 49 } 50 51 if !req.DryRun { 52 s.Log("creating updated release for %s", req.Name) 53 if err := s.env.Releases.Create(updatedRelease); err != nil { 54 return res, err 55 } 56 } 57 58 return res, nil 59 } 60 61 // prepareUpdate builds an updated release for an update operation. 62 func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*release.Release, *release.Release, error) { 63 if !ValidName.MatchString(req.Name) { 64 return nil, nil, errMissingRelease 65 } 66 67 if req.Chart == nil { 68 return nil, nil, errMissingChart 69 } 70 71 // finds the non-deleted release with the given name 72 currentRelease, err := s.env.Releases.Last(req.Name) 73 if err != nil { 74 return nil, nil, err 75 } 76 77 // If new values were not supplied in the upgrade, re-use the existing values. 78 if err := s.reuseValues(req, currentRelease); err != nil { 79 return nil, nil, err 80 } 81 82 // Increment revision count. This is passed to templates, and also stored on 83 // the release object. 84 revision := currentRelease.Version + 1 85 86 ts := timeconv.Now() 87 options := chartutil.ReleaseOptions{ 88 Name: req.Name, 89 Time: ts, 90 Namespace: currentRelease.Namespace, 91 IsUpgrade: true, 92 Revision: int(revision), 93 } 94 95 caps, err := capabilities(s.clientset.Discovery()) 96 if err != nil { 97 return nil, nil, err 98 } 99 valuesToRender, err := chartutil.ToRenderValuesCaps(req.Chart, req.Values, options, caps) 100 if err != nil { 101 return nil, nil, err 102 } 103 104 hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions) 105 if err != nil { 106 return nil, nil, err 107 } 108 109 // Store an updated release. 110 updatedRelease := &release.Release{ 111 Name: req.Name, 112 Namespace: currentRelease.Namespace, 113 Chart: req.Chart, 114 Config: req.Values, 115 Info: &release.Info{ 116 FirstDeployed: currentRelease.Info.FirstDeployed, 117 LastDeployed: ts, 118 Status: &release.Status{Code: release.Status_UNKNOWN}, 119 Description: "Preparing upgrade", // This should be overwritten later. 120 }, 121 Version: revision, 122 Manifest: manifestDoc.String(), 123 Hooks: hooks, 124 Annotations: req.Annotations, 125 } 126 127 if len(notesTxt) > 0 { 128 updatedRelease.Info.Status.Notes = notesTxt 129 } 130 err = validateManifest(s.env.KubeClient, currentRelease.Namespace, manifestDoc.Bytes()) 131 return currentRelease, updatedRelease, err 132 } 133 134 func (s *ReleaseServer) performUpdate(originalRelease, updatedRelease *release.Release, req *services.UpdateReleaseRequest) (*services.UpdateReleaseResponse, error) { 135 res := &services.UpdateReleaseResponse{Release: updatedRelease} 136 137 if req.DryRun { 138 s.Log("dry run for %s", updatedRelease.Name) 139 res.Release.Info.Description = "Dry run complete" 140 return res, nil 141 } 142 143 // pre-upgrade hooks 144 if !req.DisableHooks { 145 if err := s.execHook(updatedRelease.Hooks, updatedRelease.Name, updatedRelease.Namespace, hooks.PreUpgrade, req.Timeout); err != nil { 146 return res, err 147 } 148 } else { 149 s.Log("update hooks disabled for %s", req.Name) 150 } 151 if err := s.ReleaseModule.Update(originalRelease, updatedRelease, req, s.env); err != nil { 152 msg := fmt.Sprintf("Upgrade %q failed: %s", updatedRelease.Name, err) 153 s.Log("warning: %s", msg) 154 originalRelease.Info.Status.Code = release.Status_SUPERSEDED 155 updatedRelease.Info.Status.Code = release.Status_FAILED 156 updatedRelease.Info.Description = msg 157 s.recordRelease(originalRelease, true) 158 s.recordRelease(updatedRelease, false) 159 return res, err 160 } 161 162 // post-upgrade hooks 163 if !req.DisableHooks { 164 if err := s.execHook(updatedRelease.Hooks, updatedRelease.Name, updatedRelease.Namespace, hooks.PostUpgrade, req.Timeout); err != nil { 165 return res, err 166 } 167 } 168 169 originalRelease.Info.Status.Code = release.Status_SUPERSEDED 170 s.recordRelease(originalRelease, true) 171 172 updatedRelease.Info.Status.Code = release.Status_DEPLOYED 173 updatedRelease.Info.Description = "Upgrade complete" 174 175 return res, nil 176 }