github.com/pensu/helm@v2.6.1+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 non-deleted release with the given name 73 currentRelease, err := s.env.Releases.Last(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 // Increment revision count. This is passed to templates, and also stored on 84 // the release object. 85 revision := currentRelease.Version + 1 86 87 ts := timeconv.Now() 88 options := chartutil.ReleaseOptions{ 89 Name: req.Name, 90 Time: ts, 91 Namespace: currentRelease.Namespace, 92 IsUpgrade: true, 93 Revision: int(revision), 94 } 95 96 caps, err := capabilities(s.clientset.Discovery()) 97 if err != nil { 98 return nil, nil, err 99 } 100 valuesToRender, err := chartutil.ToRenderValuesCaps(req.Chart, req.Values, options, caps) 101 if err != nil { 102 return nil, nil, err 103 } 104 105 hooks, manifestDoc, notesTxt, err := s.renderResources(req.Chart, valuesToRender, caps.APIVersions) 106 if err != nil { 107 return nil, nil, err 108 } 109 110 // Store an updated release. 111 updatedRelease := &release.Release{ 112 Name: req.Name, 113 Namespace: currentRelease.Namespace, 114 Chart: req.Chart, 115 Config: req.Values, 116 Info: &release.Info{ 117 FirstDeployed: currentRelease.Info.FirstDeployed, 118 LastDeployed: ts, 119 Status: &release.Status{Code: release.Status_PENDING_UPGRADE}, 120 Description: "Preparing upgrade", // This should be overwritten later. 121 }, 122 Version: revision, 123 Manifest: manifestDoc.String(), 124 Hooks: hooks, 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 }