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  }