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  }