| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | Copyright The Helm Authors. | 
					
						
							|  |  |  | Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  | you may not use this file except in compliance with the License. | 
					
						
							|  |  |  | You may obtain a copy of the License at | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  | distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  | See the License for the specific language governing permissions and | 
					
						
							|  |  |  | limitations under the License. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package action | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2024-11-16 11:07:40 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | 	"log" | 
					
						
							| 
									
										
										
										
											2025-02-21 20:33:12 +08:00
										 |  |  | 	"slices" | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2019-10-17 10:01:52 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | 	"helm.sh/helm/v4/pkg/kube" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-30 19:14:09 +08:00
										 |  |  | 	"go.yaml.in/yaml/v3" | 
					
						
							| 
									
										
										
										
											2025-04-22 00:13:10 +08:00
										 |  |  | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-26 22:04:32 +08:00
										 |  |  | 	release "helm.sh/helm/v4/pkg/release/v1" | 
					
						
							| 
									
										
										
										
											2024-12-27 05:33:51 +08:00
										 |  |  | 	helmtime "helm.sh/helm/v4/pkg/time" | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // execHook executes all of the hooks for the given hook event.
 | 
					
						
							| 
									
										
										
										
											2025-04-28 12:15:46 +08:00
										 |  |  | func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent, waitStrategy kube.WaitStrategy, timeout time.Duration, serverSideApply bool) error { | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 	executingHooks := []*release.Hook{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-26 02:45:03 +08:00
										 |  |  | 	for _, h := range rl.Hooks { | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 		for _, e := range h.Events { | 
					
						
							|  |  |  | 			if e == hook { | 
					
						
							|  |  |  | 				executingHooks = append(executingHooks, h) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-17 04:43:17 +08:00
										 |  |  | 	// hooke are pre-ordered by kind, so keep order stable
 | 
					
						
							|  |  |  | 	sort.Stable(hookByWeight(executingHooks)) | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-12 22:52:14 +08:00
										 |  |  | 	for i, h := range executingHooks { | 
					
						
							| 
									
										
										
										
											2019-10-11 06:22:36 +08:00
										 |  |  | 		// Set default delete policy to before-hook-creation
 | 
					
						
							| 
									
										
										
										
											2025-05-28 01:40:46 +08:00
										 |  |  | 		cfg.hookSetDeletePolicy(h) | 
					
						
							| 
									
										
										
										
											2019-10-11 06:22:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-25 21:55:39 +08:00
										 |  |  | 		if err := cfg.deleteHookByPolicy(h, release.HookBeforeHookCreation, waitStrategy, timeout); err != nil { | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-10 05:25:47 +08:00
										 |  |  | 		resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest), true) | 
					
						
							| 
									
										
										
										
											2019-08-01 06:02:46 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2024-11-16 11:07:40 +08:00
										 |  |  | 			return fmt.Errorf("unable to build kubernetes object for %s hook %s: %w", hook, h.Path, err) | 
					
						
							| 
									
										
										
										
											2019-08-01 06:02:46 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-10 03:05:46 +08:00
										 |  |  | 		// Record the time at which the hook was applied to the cluster
 | 
					
						
							| 
									
										
										
										
											2019-07-26 02:45:03 +08:00
										 |  |  | 		h.LastRun = release.HookExecution{ | 
					
						
							| 
									
										
										
										
											2019-10-17 10:01:52 +08:00
										 |  |  | 			StartedAt: helmtime.Now(), | 
					
						
							| 
									
										
										
										
											2019-08-10 03:05:46 +08:00
										 |  |  | 			Phase:     release.HookPhaseRunning, | 
					
						
							| 
									
										
										
										
											2019-07-26 02:45:03 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-08-10 03:05:46 +08:00
										 |  |  | 		cfg.recordRelease(rl) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// As long as the implementation of WatchUntilReady does not panic, HookPhaseFailed or HookPhaseSucceeded
 | 
					
						
							|  |  |  | 		// should always be set by this function. If we fail to do that for any reason, then HookPhaseUnknown is
 | 
					
						
							|  |  |  | 		// the most appropriate value to surface.
 | 
					
						
							|  |  |  | 		h.LastRun.Phase = release.HookPhaseUnknown | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Create hook resources
 | 
					
						
							| 
									
										
										
										
											2025-07-04 03:59:23 +08:00
										 |  |  | 		if _, err := cfg.KubeClient.Create( | 
					
						
							|  |  |  | 			resources, | 
					
						
							| 
									
										
										
										
											2025-04-28 12:15:46 +08:00
										 |  |  | 			kube.ClientCreateOptionServerSideApply(serverSideApply, false)); err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-17 10:01:52 +08:00
										 |  |  | 			h.LastRun.CompletedAt = helmtime.Now() | 
					
						
							| 
									
										
										
										
											2019-08-10 03:05:46 +08:00
										 |  |  | 			h.LastRun.Phase = release.HookPhaseFailed | 
					
						
							| 
									
										
										
										
											2024-11-16 11:07:40 +08:00
										 |  |  | 			return fmt.Errorf("warning: Hook %s %s failed: %w", hook, h.Path, err) | 
					
						
							| 
									
										
										
										
											2019-08-10 03:05:46 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-25 21:55:39 +08:00
										 |  |  | 		waiter, err := cfg.KubeClient.GetWaiter(waitStrategy) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2025-04-22 00:17:50 +08:00
										 |  |  | 			return fmt.Errorf("unable to get waiter: %w", err) | 
					
						
							| 
									
										
										
										
											2025-03-25 21:55:39 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-08-10 03:05:46 +08:00
										 |  |  | 		// Watch hook resources until they have completed
 | 
					
						
							| 
									
										
										
										
											2025-03-25 21:55:39 +08:00
										 |  |  | 		err = waiter.WatchUntilReady(resources, timeout) | 
					
						
							| 
									
										
										
										
											2019-08-08 02:33:02 +08:00
										 |  |  | 		// Note the time of success/failure
 | 
					
						
							| 
									
										
										
										
											2019-10-17 10:01:52 +08:00
										 |  |  | 		h.LastRun.CompletedAt = helmtime.Now() | 
					
						
							| 
									
										
										
										
											2019-08-08 02:33:02 +08:00
										 |  |  | 		// Mark hook as succeeded or failed
 | 
					
						
							| 
									
										
										
										
											2019-07-26 02:45:03 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2019-08-08 02:33:02 +08:00
										 |  |  | 			h.LastRun.Phase = release.HookPhaseFailed | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | 			// If a hook is failed, check the annotation of the hook to determine if we should copy the logs client side
 | 
					
						
							|  |  |  | 			if errOutputting := cfg.outputLogsByPolicy(h, rl.Namespace, release.HookOutputOnFailed); errOutputting != nil { | 
					
						
							|  |  |  | 				// We log the error here as we want to propagate the hook failure upwards to the release object.
 | 
					
						
							|  |  |  | 				log.Printf("error outputting logs for hook failure: %v", errOutputting) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-08-08 02:33:02 +08:00
										 |  |  | 			// If a hook is failed, check the annotation of the hook to determine whether the hook should be deleted
 | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 			// under failed condition. If so, then clear the corresponding resource object in the hook
 | 
					
						
							| 
									
										
										
										
											2025-03-25 21:55:39 +08:00
										 |  |  | 			if errDeleting := cfg.deleteHookByPolicy(h, release.HookFailed, waitStrategy, timeout); errDeleting != nil { | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | 				// We log the error here as we want to propagate the hook failure upwards to the release object.
 | 
					
						
							| 
									
										
										
										
											2025-02-21 02:34:54 +08:00
										 |  |  | 				log.Printf("error deleting the hook resource on hook failure: %v", errDeleting) | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-09-12 22:52:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-15 06:11:45 +08:00
										 |  |  | 			// If a hook is failed, check the annotation of the previous successful hooks to determine whether the hooks
 | 
					
						
							| 
									
										
										
										
											2022-09-12 22:52:14 +08:00
										 |  |  | 			// should be deleted under succeeded condition.
 | 
					
						
							| 
									
										
										
										
											2025-04-17 18:32:51 +08:00
										 |  |  | 			if err := cfg.deleteHooksByPolicy(executingHooks[0:i], release.HookSucceeded, waitStrategy, timeout); err != nil { | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-09-12 22:52:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-08-08 02:33:02 +08:00
										 |  |  | 		h.LastRun.Phase = release.HookPhaseSucceeded | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-08 02:33:02 +08:00
										 |  |  | 	// If all hooks are successful, check the annotation of each hook to determine whether the hook should be deleted
 | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | 	// or output should be logged under succeeded condition. If so, then clear the corresponding resource object in each hook
 | 
					
						
							| 
									
										
										
										
											2024-10-31 00:48:17 +08:00
										 |  |  | 	for i := len(executingHooks) - 1; i >= 0; i-- { | 
					
						
							|  |  |  | 		h := executingHooks[i] | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | 		if err := cfg.outputLogsByPolicy(h, rl.Namespace, release.HookOutputOnSucceeded); err != nil { | 
					
						
							|  |  |  | 			// We log here as we still want to attempt hook resource deletion even if output logging fails.
 | 
					
						
							|  |  |  | 			log.Printf("error outputting logs for hook failure: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-03-25 21:55:39 +08:00
										 |  |  | 		if err := cfg.deleteHookByPolicy(h, release.HookSucceeded, waitStrategy, timeout); err != nil { | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // hookByWeight is a sorter for hooks
 | 
					
						
							|  |  |  | type hookByWeight []*release.Hook | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (x hookByWeight) Len() int      { return len(x) } | 
					
						
							|  |  |  | func (x hookByWeight) Swap(i, j int) { x[i], x[j] = x[j], x[i] } | 
					
						
							|  |  |  | func (x hookByWeight) Less(i, j int) bool { | 
					
						
							|  |  |  | 	if x[i].Weight == x[j].Weight { | 
					
						
							|  |  |  | 		return x[i].Name < x[j].Name | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return x[i].Weight < x[j].Weight | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // deleteHookByPolicy deletes a hook if the hook policy instructs it to
 | 
					
						
							| 
									
										
										
										
											2025-03-25 21:55:39 +08:00
										 |  |  | func (cfg *Configuration) deleteHookByPolicy(h *release.Hook, policy release.HookDeletePolicy, waitStrategy kube.WaitStrategy, timeout time.Duration) error { | 
					
						
							| 
									
										
										
										
											2019-10-11 06:30:49 +08:00
										 |  |  | 	// Never delete CustomResourceDefinitions; this could cause lots of
 | 
					
						
							|  |  |  | 	// cascading garbage collection.
 | 
					
						
							|  |  |  | 	if h.Kind == "CustomResourceDefinition" { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-05-28 01:40:46 +08:00
										 |  |  | 	if cfg.hookHasDeletePolicy(h, policy) { | 
					
						
							| 
									
										
										
										
											2019-10-09 03:55:19 +08:00
										 |  |  | 		resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest), false) | 
					
						
							| 
									
										
										
										
											2019-08-01 06:02:46 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2024-11-16 11:07:40 +08:00
										 |  |  | 			return fmt.Errorf("unable to build kubernetes object for deleting hook %s: %w", h.Path, err) | 
					
						
							| 
									
										
										
										
											2019-08-01 06:02:46 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		_, errs := cfg.KubeClient.Delete(resources) | 
					
						
							| 
									
										
										
										
											2019-08-14 03:10:31 +08:00
										 |  |  | 		if len(errs) > 0 { | 
					
						
							| 
									
										
										
										
											2024-11-16 11:07:40 +08:00
										 |  |  | 			return joinErrors(errs, "; ") | 
					
						
							| 
									
										
										
										
											2019-08-14 03:10:31 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-09-26 16:53:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-25 21:55:39 +08:00
										 |  |  | 		waiter, err := cfg.KubeClient.GetWaiter(waitStrategy) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err := waiter.WaitForDelete(resources, timeout); err != nil { | 
					
						
							| 
									
										
										
										
											2025-01-06 22:12:34 +08:00
										 |  |  | 			return err | 
					
						
							| 
									
										
										
										
											2022-09-26 16:53:05 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-15 06:11:45 +08:00
										 |  |  | // deleteHooksByPolicy deletes all hooks if the hook policy instructs it to
 | 
					
						
							| 
									
										
										
										
											2025-04-17 18:32:51 +08:00
										 |  |  | func (cfg *Configuration) deleteHooksByPolicy(hooks []*release.Hook, policy release.HookDeletePolicy, waitStrategy kube.WaitStrategy, timeout time.Duration) error { | 
					
						
							| 
									
										
										
										
											2025-03-15 06:11:45 +08:00
										 |  |  | 	for _, h := range hooks { | 
					
						
							| 
									
										
										
										
											2025-04-17 18:32:51 +08:00
										 |  |  | 		if err := cfg.deleteHookByPolicy(h, policy, waitStrategy, timeout); err != nil { | 
					
						
							| 
									
										
										
										
											2025-03-15 06:11:45 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-03-15 06:11:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // hookHasDeletePolicy determines whether the defined hook deletion policy matches the hook deletion polices
 | 
					
						
							|  |  |  | // supported by helm. If so, mark the hook as one should be deleted.
 | 
					
						
							| 
									
										
										
										
											2025-05-28 01:40:46 +08:00
										 |  |  | func (cfg *Configuration) hookHasDeletePolicy(h *release.Hook, policy release.HookDeletePolicy) bool { | 
					
						
							|  |  |  | 	cfg.mutex.Lock() | 
					
						
							|  |  |  | 	defer cfg.mutex.Unlock() | 
					
						
							| 
									
										
										
										
											2025-05-02 09:43:25 +08:00
										 |  |  | 	return slices.Contains(h.DeletePolicies, policy) | 
					
						
							| 
									
										
										
										
											2019-07-21 00:05:02 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-04 23:54:30 +08:00
										 |  |  | // hookSetDeletePolicy determines whether the defined hook deletion policy matches the hook deletion polices
 | 
					
						
							| 
									
										
										
										
											2025-05-28 01:40:46 +08:00
										 |  |  | // supported by helm. If so, mark the hook as one should be deleted.
 | 
					
						
							|  |  |  | func (cfg *Configuration) hookSetDeletePolicy(h *release.Hook) { | 
					
						
							|  |  |  | 	cfg.mutex.Lock() | 
					
						
							|  |  |  | 	defer cfg.mutex.Unlock() | 
					
						
							|  |  |  | 	if len(h.DeletePolicies) == 0 { | 
					
						
							|  |  |  | 		// TODO(jlegrone): Only apply before-hook-creation delete policy to run to completion
 | 
					
						
							|  |  |  | 		//                 resources. For all other resource types update in place if a
 | 
					
						
							|  |  |  | 		//                 resource with the same name already exists and is owned by the
 | 
					
						
							|  |  |  | 		//                 current release.
 | 
					
						
							|  |  |  | 		h.DeletePolicies = []release.HookDeletePolicy{release.HookBeforeHookCreation} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | // outputLogsByPolicy outputs a pods logs if the hook policy instructs it to
 | 
					
						
							|  |  |  | func (cfg *Configuration) outputLogsByPolicy(h *release.Hook, releaseNamespace string, policy release.HookOutputLogPolicy) error { | 
					
						
							| 
									
										
										
										
											2025-02-21 01:36:11 +08:00
										 |  |  | 	if !hookHasOutputLogPolicy(h, policy) { | 
					
						
							| 
									
										
										
										
											2025-02-21 20:33:12 +08:00
										 |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2025-02-21 01:36:11 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-02-21 20:33:12 +08:00
										 |  |  | 	namespace, err := cfg.deriveNamespace(h, releaseNamespace) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	switch h.Kind { | 
					
						
							|  |  |  | 	case "Job": | 
					
						
							|  |  |  | 		return cfg.outputContainerLogsForListOptions(namespace, metav1.ListOptions{LabelSelector: fmt.Sprintf("job-name=%s", h.Name)}) | 
					
						
							|  |  |  | 	case "Pod": | 
					
						
							|  |  |  | 		return cfg.outputContainerLogsForListOptions(namespace, metav1.ListOptions{FieldSelector: fmt.Sprintf("metadata.name=%s", h.Name)}) | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (cfg *Configuration) outputContainerLogsForListOptions(namespace string, listOptions metav1.ListOptions) error { | 
					
						
							| 
									
										
										
										
											2025-01-14 19:09:40 +08:00
										 |  |  | 	// TODO Helm 4: Remove this check when GetPodList and OutputContainerLogsForPodList are moved from InterfaceLogs to Interface
 | 
					
						
							| 
									
										
										
										
											2025-01-14 18:49:28 +08:00
										 |  |  | 	if kubeClient, ok := cfg.KubeClient.(kube.InterfaceLogs); ok { | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | 		podList, err := kubeClient.GetPodList(namespace, listOptions) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-02-21 20:33:12 +08:00
										 |  |  | 		err = kubeClient.OutputContainerLogsForPodList(podList, namespace, cfg.HookOutputFunc) | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (cfg *Configuration) deriveNamespace(h *release.Hook, namespace string) (string, error) { | 
					
						
							| 
									
										
										
										
											2025-02-21 20:33:12 +08:00
										 |  |  | 	tmp := struct { | 
					
						
							|  |  |  | 		Metadata struct { | 
					
						
							|  |  |  | 			Namespace string | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}{} | 
					
						
							|  |  |  | 	err := yaml.Unmarshal([]byte(h.Manifest), &tmp) | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2025-04-22 00:17:50 +08:00
										 |  |  | 		return "", fmt.Errorf("unable to parse metadata.namespace from kubernetes manifest for output logs hook %s: %w", h.Path, err) | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-02-21 20:33:12 +08:00
										 |  |  | 	if tmp.Metadata.Namespace == "" { | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | 		return namespace, nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-02-21 20:33:12 +08:00
										 |  |  | 	return tmp.Metadata.Namespace, nil | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // hookHasOutputLogPolicy determines whether the defined hook output log policy matches the hook output log policies
 | 
					
						
							|  |  |  | // supported by helm.
 | 
					
						
							|  |  |  | func hookHasOutputLogPolicy(h *release.Hook, policy release.HookOutputLogPolicy) bool { | 
					
						
							| 
									
										
										
										
											2025-02-21 20:33:12 +08:00
										 |  |  | 	return slices.Contains(h.OutputLogPolicies, policy) | 
					
						
							| 
									
										
										
										
											2022-01-07 21:37:19 +08:00
										 |  |  | } |