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 }