github.com/zoumo/helm@v2.5.0+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  	return resp.Info.Status.Resources, err
   128  }
   129  
   130  // Delete calls rudder.DeleteRelease
   131  func (m *RemoteReleaseModule) Delete(r *release.Release, req *services.UninstallReleaseRequest, env *environment.Environment) (string, []error) {
   132  	deleteRequest := &rudderAPI.DeleteReleaseRequest{Release: r}
   133  	resp, err := rudder.DeleteRelease(deleteRequest)
   134  	if err != nil {
   135  		return resp.Release.Manifest, []error{err}
   136  	}
   137  	return resp.Release.Manifest, []error{}
   138  }
   139  
   140  // DeleteRelease is a helper that allows Rudder to delete a release without exposing most of Tiller inner functions
   141  func DeleteRelease(rel *release.Release, vs chartutil.VersionSet, kubeClient environment.KubeClient) (kept string, errs []error) {
   142  	manifests := relutil.SplitManifests(rel.Manifest)
   143  	_, files, err := sortManifests(manifests, vs, UninstallOrder)
   144  	if err != nil {
   145  		// We could instead just delete everything in no particular order.
   146  		// FIXME: One way to delete at this point would be to try a label-based
   147  		// deletion. The problem with this is that we could get a false positive
   148  		// and delete something that was not legitimately part of this release.
   149  		return rel.Manifest, []error{fmt.Errorf("corrupted release record. You must manually delete the resources: %s", err)}
   150  	}
   151  
   152  	filesToKeep, filesToDelete := filterManifestsToKeep(files)
   153  	if len(filesToKeep) > 0 {
   154  		kept = summarizeKeptManifests(filesToKeep)
   155  	}
   156  
   157  	errs = []error{}
   158  	for _, file := range filesToDelete {
   159  		b := bytes.NewBufferString(strings.TrimSpace(file.content))
   160  		if b.Len() == 0 {
   161  			continue
   162  		}
   163  		if err := kubeClient.Delete(rel.Namespace, b); err != nil {
   164  			log.Printf("uninstall: Failed deletion of %q: %s", rel.Name, err)
   165  			if err == kube.ErrNoObjectsVisited {
   166  				// Rewrite the message from "no objects visited"
   167  				err = errors.New("object not found, skipping delete")
   168  			}
   169  			errs = append(errs, err)
   170  		}
   171  	}
   172  	return kept, errs
   173  }