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