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 }