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