Only get logs if --logs is given

Signed-off-by: Simon Alling <alling.simon@gmail.com>
pull/9677/head
Simon Alling 4 years ago
parent 73000df8dd
commit b0a6828ac7

@ -76,7 +76,7 @@ func main() {
// run when each command's execute method is called // run when each command's execute method is called
cobra.OnInitialize(func() { cobra.OnInitialize(func() {
helmDriver := os.Getenv("HELM_DRIVER") helmDriver := os.Getenv("HELM_DRIVER")
if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), helmDriver, debug); err != nil { if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), helmDriver, debug, actionConfig.GetHookLogFromRealCluster); err != nil {
log.Fatal(err) log.Fatal(err)
} }
if helmDriver == "memory" { if helmDriver == "memory" {

@ -120,8 +120,9 @@ func executeActionCommandStdinC(store *storage.Storage, in *os.File, cmd string)
KubeClient: &kubefake.PrintingKubeClient{Out: ioutil.Discard}, KubeClient: &kubefake.PrintingKubeClient{Out: ioutil.Discard},
Capabilities: chartutil.DefaultCapabilities, Capabilities: chartutil.DefaultCapabilities,
Log: func(format string, v ...interface{}) {}, Log: func(format string, v ...interface{}) {},
GetHookLog: func(rel *release.Release, hook *release.Hook) (release.HookLog, error) { HookLogGetter: func(rel *release.Release, hook *release.Hook) (*release.HookLog, error) {
return release.HookLog("example test pod log output"), nil hookLog := release.HookLog("example test pod log output")
return &hookLog, nil
}, },
} }

@ -71,7 +71,7 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
ValidArgsFunction: noCompletions, ValidArgsFunction: noCompletions,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if client.AllNamespaces { if client.AllNamespaces {
if err := cfg.Init(settings.RESTClientGetter(), "", os.Getenv("HELM_DRIVER"), debug); err != nil { if err := cfg.Init(settings.RESTClientGetter(), "", os.Getenv("HELM_DRIVER"), debug, cfg.GetHookLogFromRealCluster); err != nil {
return err return err
} }
} }

@ -55,6 +55,9 @@ func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command
return compListReleases(toComplete, args, cfg) return compListReleases(toComplete, args, cfg)
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if !outputLogs {
cfg.HookLogGetter = cfg.GetNoHookLogAtAll
}
client.Namespace = settings.Namespace() client.Namespace = settings.Namespace()
notName := regexp.MustCompile(`^!\s?name=`) notName := regexp.MustCompile(`^!\s?name=`)
for _, f := range filter { for _, f := range filter {
@ -76,9 +79,6 @@ func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command
return err return err
} }
// The logs are always included when JSON or YAML output is used.
// With table output, we print logs if and only if explicitly requested,
// to preserve backwards compatibility.
if outfmt == output.Table && outputLogs { if outfmt == output.Table && outputLogs {
// Print a newline to stdout to separate the output // Print a newline to stdout to separate the output
fmt.Fprintln(out) fmt.Fprintln(out)
@ -93,7 +93,7 @@ func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command
f := cmd.Flags() f := cmd.Flags()
f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)")
f.BoolVar(&outputLogs, "logs", false, "dump the logs from test pods even with table output (this runs after all tests are complete, but before any cleanup)") f.BoolVar(&outputLogs, "logs", false, "dump the logs from test pods (this runs after all tests are complete, but before any cleanup)")
f.StringSliceVar(&filter, "filter", []string{}, "specify tests by attribute (currently \"name\") using attribute=value syntax or '!attribute=value' to exclude a test (can specify multiple or separate values with commas: name=test1,name=test2)") f.StringSliceVar(&filter, "filter", []string{}, "specify tests by attribute (currently \"name\") using attribute=value syntax or '!attribute=value' to exclude a test (can specify multiple or separate values with commas: name=test1,name=test2)")
bindOutputFlag(cmd, &outfmt) bindOutputFlag(cmd, &outfmt)

@ -94,9 +94,15 @@ func TestReleaseTestingYamlOutput(t *testing.T) {
tests := []cmdTestCase{ tests := []cmdTestCase{
{ {
name: "test with yaml output format", name: "test with yaml output format without logs",
cmd: "test doge --output yaml", cmd: "test doge --output yaml",
golden: "output/test-output-yaml.txt", golden: "output/test-output-yaml-without-logs.txt",
rels: mockReleases,
},
{
name: "test with yaml output format with logs",
cmd: "test doge --output yaml --logs",
golden: "output/test-output-yaml-with-logs.txt",
rels: mockReleases, rels: mockReleases,
}, },
} }

@ -0,0 +1,41 @@
chart:
files: null
lock: null
metadata:
appVersion: "1.0"
name: foo
version: 0.1.0-beta.1
schema: null
templates:
- data: YXBpVmVyc2lvbjogdjEKa2luZDogU2VjcmV0Cm1ldGFkYXRhOgogIG5hbWU6IGZpeHR1cmUK
name: templates/foo.tpl
values: null
config:
name: value
hooks:
- delete_policies:
- before-hook-creation
events:
- test
kind: Pod
last_run:
completed_at: "2021-04-20T14:00:00.000001337Z"
phase: Succeeded
started_at: "2021-04-20T13:37:00.000001337Z"
name: doge-test-pod
path: doge-test-pod
info:
deleted: ""
description: Release mock
first_deployed: "1977-09-02T22:04:05Z"
last_deployed: "1977-09-02T22:04:05Z"
notes: Some mock release notes!
status: deployed
manifest: |
apiVersion: v1
kind: Secret
metadata:
name: fixture
name: doge
namespace: default
version: 1

@ -99,9 +99,11 @@ type Configuration struct {
Log func(string, ...interface{}) Log func(string, ...interface{})
GetHookLog func(rel *release.Release, hook *release.Hook) (release.HookLog, error) HookLogGetter HookLogGetter
} }
type HookLogGetter func(rel *release.Release, hook *release.Hook) (*release.HookLog, error)
// renderResources renders the templates in a chart // renderResources renders the templates in a chart
// //
// TODO: This function is badly in need of a refactor. // TODO: This function is badly in need of a refactor.
@ -281,9 +283,14 @@ func (cfg *Configuration) getCapabilities() (*chartutil.Capabilities, error) {
return cfg.Capabilities, nil return cfg.Capabilities, nil
} }
// getHookLogFromCluster gets the log from the pod associated with the given hook, which is expected to be a test hook. // GetNoHookLogAtAll doesn't get any log.
func (cfg *Configuration) getHookLogFromCluster(rel *release.Release, hook *release.Hook) (release.HookLog, error) { func (cfg *Configuration) GetNoHookLogAtAll(rel *release.Release, hook *release.Hook) (*release.HookLog, error) {
var nothing release.HookLog return nil, nil
}
// GetHookLogFromRealCluster gets the log from the pod associated with the given hook, which is expected to be a test hook.
func (cfg *Configuration) GetHookLogFromRealCluster(rel *release.Release, hook *release.Hook) (*release.HookLog, error) {
var nothing *release.HookLog
client, err := cfg.KubernetesClientSet() client, err := cfg.KubernetesClientSet()
if err != nil { if err != nil {
return nothing, errors.Wrapf(err, "unable to create Kubernetes client set to fetch pod logs") return nothing, errors.Wrapf(err, "unable to create Kubernetes client set to fetch pod logs")
@ -298,7 +305,8 @@ func (cfg *Configuration) getHookLogFromCluster(rel *release.Release, hook *rele
if err != nil { if err != nil {
return nothing, errors.Wrapf(err, "unable to get pod logs for %s", hook.Name) return nothing, errors.Wrapf(err, "unable to get pod logs for %s", hook.Name)
} }
return release.HookLog(stringBuilder.String()), nil hookLog := release.HookLog(stringBuilder.String())
return &hookLog, nil
} }
// KubernetesClientSet creates a new kubernetes ClientSet based on the configuration // KubernetesClientSet creates a new kubernetes ClientSet based on the configuration
@ -387,7 +395,7 @@ func (cfg *Configuration) recordRelease(r *release.Release) {
} }
// Init initializes the action configuration // Init initializes the action configuration
func (cfg *Configuration) Init(getter genericclioptions.RESTClientGetter, namespace, helmDriver string, log DebugLog) error { func (cfg *Configuration) Init(getter genericclioptions.RESTClientGetter, namespace, helmDriver string, log DebugLog, hookLogGetter HookLogGetter) error {
kc := kube.New(getter) kc := kube.New(getter)
kc.Log = log kc.Log = log
@ -440,7 +448,7 @@ func (cfg *Configuration) Init(getter genericclioptions.RESTClientGetter, namesp
cfg.KubeClient = kc cfg.KubeClient = kc
cfg.Releases = store cfg.Releases = store
cfg.Log = log cfg.Log = log
cfg.GetHookLog = cfg.getHookLogFromCluster cfg.HookLogGetter = hookLogGetter
return nil return nil
} }

@ -50,8 +50,9 @@ func actionConfigFixture(t *testing.T) *Configuration {
t.Fatal(err) t.Fatal(err)
} }
mockHookLogGetter := func(rel *release.Release, hook *release.Hook) (release.HookLog, error) { mockHookLogGetter := func(rel *release.Release, hook *release.Hook) (*release.HookLog, error) {
return release.HookLog("example test pod log output"), nil hookLog := release.HookLog("example test pod log output")
return &hookLog, nil
} }
return &Configuration{ return &Configuration{
@ -65,7 +66,7 @@ func actionConfigFixture(t *testing.T) *Configuration {
t.Logf(format, v...) t.Logf(format, v...)
} }
}, },
GetHookLog: mockHookLogGetter, HookLogGetter: mockHookLogGetter,
} }
} }

@ -85,11 +85,11 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent,
h.LastRun.CompletedAt = helmtime.Now() h.LastRun.CompletedAt = helmtime.Now()
if isTestHook(h) { if isTestHook(h) {
hookLog, err := cfg.GetHookLog(rl, h) hookLog, err := cfg.HookLogGetter(rl, h)
if err != nil { if err != nil {
return err return err
} }
h.LastRun.Log = &hookLog h.LastRun.Log = hookLog
} }
// Mark hook as succeeded or failed // Mark hook as succeeded or failed

@ -102,11 +102,11 @@ func (r *ReleaseTesting) Run(name string) (*release.Release, error) {
func (r *ReleaseTesting) GetPodLogs(out io.Writer, rel *release.Release) error { func (r *ReleaseTesting) GetPodLogs(out io.Writer, rel *release.Release) error {
for _, h := range rel.Hooks { for _, h := range rel.Hooks {
if isTestHook(h) { if isTestHook(h) {
hookLog, err := r.cfg.GetHookLog(rel, h) hookLog, err := r.cfg.HookLogGetter(rel, h)
if err != nil { if err != nil {
return err return err
} }
_, err = fmt.Fprintf(out, "POD LOGS: %s\n%s\n", h.Name, string(hookLog)) _, err = fmt.Fprintf(out, "POD LOGS: %s\n%s\n", h.Name, string(*hookLog))
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to write pod logs for %s", h.Name) return errors.Wrapf(err, "unable to write pod logs for %s", h.Name)
} }

Loading…
Cancel
Save