github.com/doitroot/helm@v3.0.0-beta.3+incompatible/pkg/action/hooks.go (about) 1 /* 2 Copyright The Helm Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package action 17 18 import ( 19 "bytes" 20 "sort" 21 "time" 22 23 "github.com/pkg/errors" 24 25 "helm.sh/helm/pkg/release" 26 ) 27 28 // execHook executes all of the hooks for the given hook event. 29 func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent, timeout time.Duration) error { 30 executingHooks := []*release.Hook{} 31 32 for _, h := range rl.Hooks { 33 for _, e := range h.Events { 34 if e == hook { 35 executingHooks = append(executingHooks, h) 36 } 37 } 38 } 39 40 sort.Sort(hookByWeight(executingHooks)) 41 42 for _, h := range executingHooks { 43 if err := cfg.deleteHookByPolicy(h, release.HookBeforeHookCreation); err != nil { 44 return err 45 } 46 47 resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest)) 48 if err != nil { 49 return errors.Wrapf(err, "unable to build kubernetes object for %s hook %s", hook, h.Path) 50 } 51 52 // Record the time at which the hook was applied to the cluster 53 h.LastRun = release.HookExecution{ 54 StartedAt: time.Now(), 55 Phase: release.HookPhaseRunning, 56 } 57 cfg.recordRelease(rl) 58 59 // As long as the implementation of WatchUntilReady does not panic, HookPhaseFailed or HookPhaseSucceeded 60 // should always be set by this function. If we fail to do that for any reason, then HookPhaseUnknown is 61 // the most appropriate value to surface. 62 h.LastRun.Phase = release.HookPhaseUnknown 63 64 // Create hook resources 65 if _, err := cfg.KubeClient.Create(resources); err != nil { 66 h.LastRun.CompletedAt = time.Now() 67 h.LastRun.Phase = release.HookPhaseFailed 68 return errors.Wrapf(err, "warning: Hook %s %s failed", hook, h.Path) 69 } 70 71 // Watch hook resources until they have completed 72 err = cfg.KubeClient.WatchUntilReady(resources, timeout) 73 // Note the time of success/failure 74 h.LastRun.CompletedAt = time.Now() 75 // Mark hook as succeeded or failed 76 if err != nil { 77 h.LastRun.Phase = release.HookPhaseFailed 78 // If a hook is failed, check the annotation of the hook to determine whether the hook should be deleted 79 // under failed condition. If so, then clear the corresponding resource object in the hook 80 if err := cfg.deleteHookByPolicy(h, release.HookFailed); err != nil { 81 return err 82 } 83 return err 84 } 85 h.LastRun.Phase = release.HookPhaseSucceeded 86 } 87 88 // If all hooks are successful, check the annotation of each hook to determine whether the hook should be deleted 89 // under succeeded condition. If so, then clear the corresponding resource object in each hook 90 for _, h := range executingHooks { 91 if err := cfg.deleteHookByPolicy(h, release.HookSucceeded); err != nil { 92 return err 93 } 94 } 95 96 return nil 97 } 98 99 // hookByWeight is a sorter for hooks 100 type hookByWeight []*release.Hook 101 102 func (x hookByWeight) Len() int { return len(x) } 103 func (x hookByWeight) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 104 func (x hookByWeight) Less(i, j int) bool { 105 if x[i].Weight == x[j].Weight { 106 return x[i].Name < x[j].Name 107 } 108 return x[i].Weight < x[j].Weight 109 } 110 111 // deleteHookByPolicy deletes a hook if the hook policy instructs it to 112 func (cfg *Configuration) deleteHookByPolicy(h *release.Hook, policy release.HookDeletePolicy) error { 113 if hookHasDeletePolicy(h, policy) { 114 resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest)) 115 if err != nil { 116 return errors.Wrapf(err, "unable to build kubernetes object for deleting hook %s", h.Path) 117 } 118 _, errs := cfg.KubeClient.Delete(resources) 119 if len(errs) > 0 { 120 return errors.New(joinErrors(errs)) 121 } 122 } 123 return nil 124 } 125 126 // hookHasDeletePolicy determines whether the defined hook deletion policy matches the hook deletion polices 127 // supported by helm. If so, mark the hook as one should be deleted. 128 func hookHasDeletePolicy(h *release.Hook, policy release.HookDeletePolicy) bool { 129 for _, v := range h.DeletePolicies { 130 if policy == v { 131 return true 132 } 133 } 134 return false 135 }