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  }