github.com/migueleliasweb/helm@v2.6.1+incompatible/pkg/tiller/release_rollback.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/hooks"
    25  	"k8s.io/helm/pkg/proto/hapi/release"
    26  	"k8s.io/helm/pkg/proto/hapi/services"
    27  	"k8s.io/helm/pkg/timeconv"
    28  )
    29  
    30  // RollbackRelease rolls back to a previous version of the given release.
    31  func (s *ReleaseServer) RollbackRelease(c ctx.Context, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) {
    32  	s.Log("preparing rollback of %s", req.Name)
    33  	currentRelease, targetRelease, err := s.prepareRollback(req)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	if !req.DryRun {
    39  		s.Log("creating rolled back release for %s", req.Name)
    40  		if err := s.env.Releases.Create(targetRelease); err != nil {
    41  			return nil, err
    42  		}
    43  	}
    44  	s.Log("performing rollback of %s", req.Name)
    45  	res, err := s.performRollback(currentRelease, targetRelease, req)
    46  	if err != nil {
    47  		return res, err
    48  	}
    49  
    50  	if !req.DryRun {
    51  		s.Log("updating status for rolled back release for %s", req.Name)
    52  		if err := s.env.Releases.Update(targetRelease); err != nil {
    53  			return res, err
    54  		}
    55  	}
    56  
    57  	return res, nil
    58  }
    59  
    60  // prepareRollback finds the previous release and prepares a new release object with
    61  // the previous release's configuration
    62  func (s *ReleaseServer) prepareRollback(req *services.RollbackReleaseRequest) (*release.Release, *release.Release, error) {
    63  	if err := validateReleaseName(req.Name); err != nil {
    64  		s.Log("prepareRollback: Release name is invalid: %s", req.Name)
    65  		return nil, nil, err
    66  	}
    67  
    68  	if req.Version < 0 {
    69  		return nil, nil, errInvalidRevision
    70  	}
    71  
    72  	crls, err := s.env.Releases.Last(req.Name)
    73  	if err != nil {
    74  		return nil, nil, err
    75  	}
    76  
    77  	rbv := req.Version
    78  	if req.Version == 0 {
    79  		rbv = crls.Version - 1
    80  	}
    81  
    82  	s.Log("rolling back %s (current: v%d, target: v%d)", req.Name, crls.Version, rbv)
    83  
    84  	prls, err := s.env.Releases.Get(req.Name, rbv)
    85  	if err != nil {
    86  		return nil, nil, err
    87  	}
    88  
    89  	// Store a new release object with previous release's configuration
    90  	target := &release.Release{
    91  		Name:      req.Name,
    92  		Namespace: crls.Namespace,
    93  		Chart:     prls.Chart,
    94  		Config:    prls.Config,
    95  		Info: &release.Info{
    96  			FirstDeployed: crls.Info.FirstDeployed,
    97  			LastDeployed:  timeconv.Now(),
    98  			Status: &release.Status{
    99  				Code:  release.Status_PENDING_ROLLBACK,
   100  				Notes: prls.Info.Status.Notes,
   101  			},
   102  			// Because we lose the reference to rbv elsewhere, we set the
   103  			// message here, and only override it later if we experience failure.
   104  			Description: fmt.Sprintf("Rollback to %d", rbv),
   105  		},
   106  		Version:  crls.Version + 1,
   107  		Manifest: prls.Manifest,
   108  		Hooks:    prls.Hooks,
   109  	}
   110  
   111  	return crls, target, nil
   112  }
   113  
   114  func (s *ReleaseServer) performRollback(currentRelease, targetRelease *release.Release, req *services.RollbackReleaseRequest) (*services.RollbackReleaseResponse, error) {
   115  	res := &services.RollbackReleaseResponse{Release: targetRelease}
   116  
   117  	if req.DryRun {
   118  		s.Log("dry run for %s", targetRelease.Name)
   119  		return res, nil
   120  	}
   121  
   122  	// pre-rollback hooks
   123  	if !req.DisableHooks {
   124  		if err := s.execHook(targetRelease.Hooks, targetRelease.Name, targetRelease.Namespace, hooks.PreRollback, req.Timeout); err != nil {
   125  			return res, err
   126  		}
   127  	} else {
   128  		s.Log("rollback hooks disabled for %s", req.Name)
   129  	}
   130  
   131  	if err := s.ReleaseModule.Rollback(currentRelease, targetRelease, req, s.env); err != nil {
   132  		msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err)
   133  		s.Log("warning: %s", msg)
   134  		currentRelease.Info.Status.Code = release.Status_SUPERSEDED
   135  		targetRelease.Info.Status.Code = release.Status_FAILED
   136  		targetRelease.Info.Description = msg
   137  		s.recordRelease(currentRelease, true)
   138  		s.recordRelease(targetRelease, false)
   139  		return res, err
   140  	}
   141  
   142  	// post-rollback hooks
   143  	if !req.DisableHooks {
   144  		if err := s.execHook(targetRelease.Hooks, targetRelease.Name, targetRelease.Namespace, hooks.PostRollback, req.Timeout); err != nil {
   145  			return res, err
   146  		}
   147  	}
   148  
   149  	currentRelease.Info.Status.Code = release.Status_SUPERSEDED
   150  	s.recordRelease(currentRelease, true)
   151  
   152  	targetRelease.Info.Status.Code = release.Status_DEPLOYED
   153  
   154  	return res, nil
   155  }