github.com/Beeketing/helm@v2.12.1+incompatible/pkg/tiller/release_modules.go (about)

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