github.com/wangchanggan/helm@v0.0.0-20211020154240-11b1b7d5406d/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  // 将Chart内容编译成字节流,然后通过client-go无结构体提交给ApiServer
    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.UpdateWithOptions(target.Namespace, c, t, kube.UpdateOptions{
    63  		Force:         req.Force,
    64  		Recreate:      req.Recreate,
    65  		Timeout:       req.Timeout,
    66  		ShouldWait:    req.Wait,
    67  		CleanupOnFail: req.CleanupOnFail,
    68  	})
    69  }
    70  
    71  // Rollback performs a rollback from current to target release
    72  func (m *LocalReleaseModule) Rollback(current, target *release.Release, req *services.RollbackReleaseRequest, env *environment.Environment) error {
    73  	c := bytes.NewBufferString(current.Manifest)
    74  	t := bytes.NewBufferString(target.Manifest)
    75  	return env.KubeClient.UpdateWithOptions(target.Namespace, c, t, kube.UpdateOptions{
    76  		Force:         req.Force,
    77  		Recreate:      req.Recreate,
    78  		Timeout:       req.Timeout,
    79  		ShouldWait:    req.Wait,
    80  		CleanupOnFail: req.CleanupOnFail,
    81  	})
    82  }
    83  
    84  // Status returns kubectl-like formatted status of release objects
    85  func (m *LocalReleaseModule) Status(r *release.Release, req *services.GetReleaseStatusRequest, env *environment.Environment) (string, error) {
    86  	return env.KubeClient.Get(r.Namespace, bytes.NewBufferString(r.Manifest))
    87  }
    88  
    89  // Delete deletes the release and returns manifests that were kept in the deletion process
    90  func (m *LocalReleaseModule) Delete(rel *release.Release, req *services.UninstallReleaseRequest, env *environment.Environment) (kept string, errs []error) {
    91  	vs, err := GetVersionSet(m.clientset.Discovery())
    92  	if err != nil {
    93  		return rel.Manifest, []error{fmt.Errorf("Could not get apiVersions from Kubernetes: %v", err)}
    94  	}
    95  	return DeleteRelease(rel, vs, env.KubeClient)
    96  }
    97  
    98  // RemoteReleaseModule is a ReleaseModule which calls Rudder service to operate on a release
    99  type RemoteReleaseModule struct{}
   100  
   101  // Create calls rudder.InstallRelease
   102  func (m *RemoteReleaseModule) Create(r *release.Release, req *services.InstallReleaseRequest, env *environment.Environment) error {
   103  	request := &rudderAPI.InstallReleaseRequest{Release: r}
   104  	_, err := rudder.InstallRelease(request)
   105  	return err
   106  }
   107  
   108  // Update calls rudder.UpgradeRelease
   109  func (m *RemoteReleaseModule) Update(current, target *release.Release, req *services.UpdateReleaseRequest, env *environment.Environment) error {
   110  	upgrade := &rudderAPI.UpgradeReleaseRequest{
   111  		Current:  current,
   112  		Target:   target,
   113  		Recreate: req.Recreate,
   114  		Timeout:  req.Timeout,
   115  		Wait:     req.Wait,
   116  		Force:    req.Force,
   117  	}
   118  	_, err := rudder.UpgradeRelease(upgrade)
   119  	return err
   120  }
   121  
   122  // Rollback calls rudder.Rollback
   123  func (m *RemoteReleaseModule) Rollback(current, target *release.Release, req *services.RollbackReleaseRequest, env *environment.Environment) error {
   124  	rollback := &rudderAPI.RollbackReleaseRequest{
   125  		Current:  current,
   126  		Target:   target,
   127  		Recreate: req.Recreate,
   128  		Timeout:  req.Timeout,
   129  		Wait:     req.Wait,
   130  	}
   131  	_, err := rudder.RollbackRelease(rollback)
   132  	return err
   133  }
   134  
   135  // Status returns status retrieved from rudder.ReleaseStatus
   136  func (m *RemoteReleaseModule) Status(r *release.Release, req *services.GetReleaseStatusRequest, env *environment.Environment) (string, error) {
   137  	statusRequest := &rudderAPI.ReleaseStatusRequest{Release: r}
   138  	resp, err := rudder.ReleaseStatus(statusRequest)
   139  	if resp == nil {
   140  		return "", err
   141  	}
   142  	return resp.Info.Status.Resources, err
   143  }
   144  
   145  // Delete calls rudder.DeleteRelease
   146  func (m *RemoteReleaseModule) Delete(r *release.Release, req *services.UninstallReleaseRequest, env *environment.Environment) (string, []error) {
   147  	deleteRequest := &rudderAPI.DeleteReleaseRequest{Release: r}
   148  	resp, err := rudder.DeleteRelease(deleteRequest)
   149  
   150  	errs := make([]error, 0)
   151  	result := ""
   152  
   153  	if err != nil {
   154  		errs = append(errs, err)
   155  	}
   156  	if resp != nil {
   157  		result = resp.Release.Manifest
   158  	}
   159  	return result, errs
   160  }
   161  
   162  // DeleteRelease is a helper that allows Rudder to delete a release without exposing most of Tiller inner functions
   163  func DeleteRelease(rel *release.Release, vs chartutil.VersionSet, kubeClient environment.KubeClient) (kept string, errs []error) {
   164  	manifests := relutil.SplitManifests(rel.Manifest)
   165  	_, files, err := sortManifests(manifests, vs, UninstallOrder)
   166  	if err != nil {
   167  		// We could instead just delete everything in no particular order.
   168  		// FIXME: One way to delete at this point would be to try a label-based
   169  		// deletion. The problem with this is that we could get a false positive
   170  		// and delete something that was not legitimately part of this release.
   171  		return rel.Manifest, []error{fmt.Errorf("corrupted release record. You must manually delete the resources: %s", err)}
   172  	}
   173  
   174  	filesToKeep, filesToDelete := filterManifestsToKeep(files)
   175  	if len(filesToKeep) > 0 {
   176  		kept = summarizeKeptManifests(filesToKeep, kubeClient, rel.Namespace)
   177  	}
   178  
   179  	errs = []error{}
   180  	for _, file := range filesToDelete {
   181  		b := bytes.NewBufferString(strings.TrimSpace(file.Content))
   182  		if b.Len() == 0 {
   183  			continue
   184  		}
   185  		if err := kubeClient.Delete(rel.Namespace, b); err != nil {
   186  			log.Printf("uninstall: Failed deletion of %q: %s", rel.Name, err)
   187  			if err == kube.ErrNoObjectsVisited {
   188  				// Rewrite the message from "no objects visited"
   189  				obj := ""
   190  				if file.Head != nil && file.Head.Metadata != nil {
   191  					obj = "[" + file.Head.Kind + "] " + file.Head.Metadata.Name
   192  				}
   193  				err = fmt.Errorf("release %q: object %q not found, skipping delete", rel.Name, obj)
   194  			}
   195  			errs = append(errs, err)
   196  		}
   197  	}
   198  	return kept, errs
   199  }