feat(test): Adds --logs flag

This is a v3 port of #6612. There have been significant changes due to the way
Helm 3 refactored things. I chose to add the method for getting logs to the
testing client because it seemed like something that someone using Helm
as an SDK might want. It takes a writer because it is more efficient (less
copying) and can write to any sort of buffer desired

Signed-off-by: Taylor Thomas <taylor.thomas@microsoft.com>
pull/6693/head
Taylor Thomas 5 years ago
parent c3e356faba
commit 25697a62c4

@ -17,6 +17,7 @@ limitations under the License.
package main
import (
"fmt"
"io"
"time"
@ -36,7 +37,8 @@ The tests to be run are defined in the chart that was installed.
func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
client := action.NewReleaseTesting(cfg)
var outfmt output.Format
var outfmt = output.Table
var outputLogs bool
cmd := &cobra.Command{
Use: "test [RELEASE]",
@ -44,17 +46,34 @@ func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command
Long: releaseTestHelp,
Args: require.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
rel, err := client.Run(args[0])
if err != nil {
client.Namespace = settings.Namespace()
rel, runErr := client.Run(args[0])
// We only return an error if we weren't even able to get the
// release, otherwise we keep going so we can print status and logs
// if requested
if runErr != nil && rel == nil {
return runErr
}
if err := outfmt.Write(out, &statusPrinter{rel, settings.Debug}); err != nil {
return err
}
return outfmt.Write(out, &statusPrinter{rel, settings.Debug})
if outputLogs {
// Print a newline to stdout to separate the output
fmt.Fprintln(out)
if err := client.GetPodLogs(out, rel); err != nil {
return err
}
}
return runErr
},
}
f := cmd.Flags()
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 (this runs after all tests are complete, but before any cleanup)")
return cmd
}

@ -17,9 +17,12 @@ limitations under the License.
package action
import (
"fmt"
"io"
"time"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
"helm.sh/helm/v3/pkg/release"
)
@ -30,6 +33,8 @@ import (
type ReleaseTesting struct {
cfg *Configuration
Timeout time.Duration
// Used for fetching logs from test pods
Namespace string
}
// NewReleaseTesting creates a new ReleaseTesting object with the given configuration.
@ -62,3 +67,33 @@ func (r *ReleaseTesting) Run(name string) (*release.Release, error) {
return rel, r.cfg.Releases.Update(rel)
}
// GetPodLogs will write the logs for all test pods in the given release into
// the given writer. These can be immediately output to the user or captured for
// other uses
func (r *ReleaseTesting) GetPodLogs(out io.Writer, rel *release.Release) error {
client, err := r.cfg.KubernetesClientSet()
if err != nil {
return errors.Wrap(err, "unable to get kubernetes client to fetch pod logs")
}
for _, h := range rel.Hooks {
for _, e := range h.Events {
if e == release.HookTest {
req := client.CoreV1().Pods(r.Namespace).GetLogs(h.Name, &v1.PodLogOptions{})
logReader, err := req.Stream()
if err != nil {
return errors.Wrapf(err, "unable to get pod logs for %s", h.Name)
}
fmt.Fprintf(out, "POD LOGS: %s\n", h.Name)
_, err = io.Copy(out, logReader)
fmt.Fprintln(out)
if err != nil {
return errors.Wrapf(err, "unable to write pod logs for %s", h.Name)
}
}
}
}
return nil
}

Loading…
Cancel
Save