github.com/darkowlzz/helm@v2.5.1-0.20171213183701-6707fe0468d4+incompatible/pkg/tiller/release_modules.go (about)

     1  /*
     2  Copyright 2017 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  	"bytes"
    21  	"errors"
    22  	"fmt"
    23  	"log"
    24  	"strings"
    25  
    26  	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
    27  
    28  	"k8s.io/helm/pkg/chartutil"
    29  	"k8s.io/helm/pkg/kube"
    30  	"k8s.io/helm/pkg/proto/hapi/release"
    31  	rudderAPI "k8s.io/helm/pkg/proto/hapi/rudder"
    32  	"k8s.io/helm/pkg/proto/hapi/services"
    33  	relutil "k8s.io/helm/pkg/releaseutil"
    34  	"k8s.io/helm/pkg/rudder"
    35  	"k8s.io/helm/pkg/tiller/environment"
    36  )
    37  
    38  // ReleaseModule is an interface that allows ReleaseServer to run operations on release via either local implementation or Rudder service
    39  type ReleaseModule interface {
    40  	Create(r *release.Release, req *services.InstallReleaseRequest, env *environment.Environment) error
    41  	Update(current, target *release.Release, req *services.UpdateReleaseRequest, env *environment.Environment) error
    42  	Rollback(current, target *release.Release, req *services.RollbackReleaseRequest, env *environment.Environment) error
    43  	Status(r *release.Release, req *services.GetReleaseStatusRequest, env *environment.Environment) (string, error)
    44  	Delete(r *release.Release, req *services.UninstallReleaseRequest, env *environment.Environment) (string, []error)
    45  }
    46  
    47  // LocalReleaseModule is a local implementation of ReleaseModule
    48  type LocalReleaseModule struct {
    49  	clientset internalclientset.Interface
    50  }
    51  
    52  // Create creates a release via kubeclient from provided environment
    53  func (m *LocalReleaseModule) Create(r *release.Release, req *services.InstallReleaseRequest, env *environment.Environment) error {
    54  	b := bytes.NewBufferString(r.Manifest)
    55  	return env.KubeClient.Create(r.Namespace, b, req.Timeout, req.Wait)
    56  }
    57  
    58  // Update performs an update from current to target release
    59  func (m *LocalReleaseModule) Update(current, target *release.Release, req *services.UpdateReleaseRequest, env *environment.Environment) error {
    60  	c := bytes.NewBufferString(current.Manifest)
    61  	t := bytes.NewBufferString(target.Manifest)
    62  	return env.KubeClient.Update(target.Namespace, c, t, req.Force, req.Recreate, req.Timeout, req.Wait)
    63  }
    64  
    65  // Rollback performs a rollback from current to target release
    66  func (m *LocalReleaseModule) Rollback(current, target *release.Release, req *services.RollbackReleaseRequest, env *environment.Environment) error {
    67  	c := bytes.NewBufferString(current.Manifest)
    68  	t := bytes.NewBufferString(target.Manifest)
    69  	return env.KubeClient.Update(target.Namespace, c, t, req.Force, req.Recreate, req.Timeout, req.Wait)
    70  }
    71  
    72  // Status returns kubectl-like formatted status of release objects
    73  func (m *LocalReleaseModule) Status(r *release.Release, req *services.GetReleaseStatusRequest, env *environment.Environment) (string, error) {
    74  	return env.KubeClient.Get(r.Namespace, bytes.NewBufferString(r.Manifest))
    75  }
    76  
    77  // Delete deletes the release and returns manifests that were kept in the deletion process
    78  func (m *LocalReleaseModule) Delete(rel *release.Release, req *services.UninstallReleaseRequest, env *environment.Environment) (kept string, errs []error) {
    79  	vs, err := GetVersionSet(m.clientset.Discovery())
    80  	if err != nil {
    81  		return rel.Manifest, []error{fmt.Errorf("Could not get apiVersions from Kubernetes: %v", err)}
    82  	}
    83  	return DeleteRelease(rel, vs, env.KubeClient)
    84  }
    85  
    86  // RemoteReleaseModule is a ReleaseModule which calls Rudder service to operate on a release
    87  type RemoteReleaseModule struct{}
    88  
    89  // Create calls rudder.InstallRelease
    90  func (m *RemoteReleaseModule) Create(r *release.Release, req *services.InstallReleaseRequest, env *environment.Environment) error {
    91  	request := &rudderAPI.InstallReleaseRequest{Release: r}
    92  	_, err := rudder.InstallRelease(request)
    93  	return err
    94  }
    95  
    96  // Update calls rudder.UpgradeRelease
    97  func (m *RemoteReleaseModule) Update(current, target *release.Release, req *services.UpdateReleaseRequest, env *environment.Environment) error {
    98  	upgrade := &rudderAPI.UpgradeReleaseRequest{
    99  		Current:  current,
   100  		Target:   target,
   101  		Recreate: req.Recreate,
   102  		Timeout:  req.Timeout,
   103  		Wait:     req.Wait,
   104  		Force:    req.Force,
   105  	}
   106  	_, err := rudder.UpgradeRelease(upgrade)
   107  	return err
   108  }
   109  
   110  // Rollback calls rudder.Rollback
   111  func (m *RemoteReleaseModule) Rollback(current, target *release.Release, req *services.RollbackReleaseRequest, env *environment.Environment) error {
   112  	rollback := &rudderAPI.RollbackReleaseRequest{
   113  		Current:  current,
   114  		Target:   target,
   115  		Recreate: req.Recreate,
   116  		Timeout:  req.Timeout,
   117  		Wait:     req.Wait,
   118  	}
   119  	_, err := rudder.RollbackRelease(rollback)
   120  	return err
   121  }
   122  
   123  // Status returns status retrieved from rudder.ReleaseStatus
   124  func (m *RemoteReleaseModule) Status(r *release.Release, req *services.GetReleaseStatusRequest, env *environment.Environment) (string, error) {
   125  	statusRequest := &rudderAPI.ReleaseStatusRequest{Release: r}
   126  	resp, err := rudder.ReleaseStatus(statusRequest)
   127  	if resp == nil {
   128  		return "", err
   129  	}
   130  	return resp.Info.Status.Resources, err
   131  }
   132  
   133  // Delete calls rudder.DeleteRelease
   134  func (m *RemoteReleaseModule) Delete(r *release.Release, req *services.UninstallReleaseRequest, env *environment.Environment) (string, []error) {
   135  	deleteRequest := &rudderAPI.DeleteReleaseRequest{Release: r}
   136  	resp, err := rudder.DeleteRelease(deleteRequest)
   137  
   138  	errs := make([]error, 0)
   139  	result := ""
   140  
   141  	if err != nil {
   142  		errs = append(errs, err)
   143  	}
   144  	if resp != nil {
   145  		result = resp.Release.Manifest
   146  	}
   147  	return result, errs
   148  }
   149  
   150  // DeleteRelease is a helper that allows Rudder to delete a release without exposing most of Tiller inner functions
   151  func DeleteRelease(rel *release.Release, vs chartutil.VersionSet, kubeClient environment.KubeClient) (kept string, errs []error) {
   152  	manifests := relutil.SplitManifests(rel.Manifest)
   153  	_, files, err := sortManifests(manifests, vs, UninstallOrder)
   154  	if err != nil {
   155  		// We could instead just delete everything in no particular order.
   156  		// FIXME: One way to delete at this point would be to try a label-based
   157  		// deletion. The problem with this is that we could get a false positive
   158  		// and delete something that was not legitimately part of this release.
   159  		return rel.Manifest, []error{fmt.Errorf("corrupted release record. You must manually delete the resources: %s", err)}
   160  	}
   161  
   162  	filesToKeep, filesToDelete := filterManifestsToKeep(files)
   163  	if len(filesToKeep) > 0 {
   164  		kept = summarizeKeptManifests(filesToKeep, kubeClient, rel.Namespace)
   165  	}
   166  
   167  	errs = []error{}
   168  	for _, file := range filesToDelete {
   169  		b := bytes.NewBufferString(strings.TrimSpace(file.Content))
   170  		if b.Len() == 0 {
   171  			continue
   172  		}
   173  		if err := kubeClient.Delete(rel.Namespace, b); err != nil {
   174  			log.Printf("uninstall: Failed deletion of %q: %s", rel.Name, err)
   175  			if err == kube.ErrNoObjectsVisited {
   176  				// Rewrite the message from "no objects visited"
   177  				err = errors.New("object not found, skipping delete")
   178  			}
   179  			errs = append(errs, err)
   180  		}
   181  	}
   182  	return kept, errs
   183  }