pull/13358/merge
Charlie Getzen 10 months ago committed by GitHub
commit 43c6aaa231
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -90,7 +90,7 @@ func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command
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)")
f.BoolVar(&outputLogs, "logs", false, "dump the logs from test jobs or 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.BoolVar(&client.HideNotes, "hide-notes", false, "if set, do not show notes in test output. Does not affect presence in chart metadata")

@ -84,6 +84,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
valueOpts := &values.Options{}
var outfmt output.Format
var createNamespace bool
var outputLogs bool
cmd := &cobra.Command{
Use: "upgrade [RELEASE] [CHART]",
@ -237,22 +238,39 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
cancel()
}()
rel, err := client.RunWithContext(ctx, args[0], ch, vals)
rel, runErr := client.RunWithContext(ctx, args[0], ch, vals)
if err != nil {
return errors.Wrap(err, "UPGRADE FAILED")
// 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 errors.Wrap(runErr, "UPGRADE FAILED")
}
if outfmt == output.Table {
if runErr == nil && outfmt == output.Table {
fmt.Fprintf(out, "Release %q has been upgraded. Happy Helming!\n", args[0])
}
return outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false, false, client.HideNotes})
if err := outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false, false, client.HideNotes}); err != nil {
return err
}
if outputLogs {
// Print a newline to stdout to separate the output
fmt.Fprintln(out)
if err := client.GetHookLogs(out, rel); err != nil {
return err
}
}
if runErr != nil {
return errors.Wrap(runErr, "UPGRADE FAILED")
}
return nil
},
}
f := cmd.Flags()
f.BoolVar(&createNamespace, "create-namespace", false, "if --install is set, create the release namespace if not present")
f.BoolVar(&outputLogs, "logs", false, "dump the logs from hook jobs or pods (this runs after the upgrade completes)")
f.BoolVarP(&client.Install, "install", "i", false, "if a release by this name doesn't already exist, run an install")
f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored")
f.StringVar(&client.DryRunOption, "dry-run", "", "simulate an install. If --dry-run is set with no option being specified or as '--dry-run=client', it will not attempt cluster connections. Setting '--dry-run=server' allows attempting cluster connections.")

@ -25,6 +25,9 @@ import (
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/release"
@ -113,10 +116,9 @@ func (r *ReleaseTesting) GetPodLogs(out io.Writer, rel *release.Release) error {
if err != nil {
return errors.Wrap(err, "unable to get kubernetes client to fetch pod logs")
}
hooksByWight := append([]*release.Hook{}, rel.Hooks...)
sort.Stable(hookByWeight(hooksByWight))
for _, h := range hooksByWight {
hooksByWeight := append([]*release.Hook{}, rel.Hooks...)
sort.Stable(hookByWeight(hooksByWeight))
for _, h := range hooksByWeight {
for _, e := range h.Events {
if e == release.HookTest {
if contains(r.Filters[ExcludeNameFilter], h.Name) {
@ -125,7 +127,44 @@ func (r *ReleaseTesting) GetPodLogs(out io.Writer, rel *release.Release) error {
if len(r.Filters[IncludeNameFilter]) > 0 && !contains(r.Filters[IncludeNameFilter], h.Name) {
continue
}
req := client.CoreV1().Pods(r.Namespace).GetLogs(h.Name, &v1.PodLogOptions{})
if err := getHookLogs(out, client, r.Namespace, h); err != nil {
return err
}
}
}
}
return nil
}
func getHookLogs(out io.Writer, client kubernetes.Interface, namespace string, h *release.Hook) error {
switch kind := h.Kind; kind {
case "Job":
job, err := client.BatchV1().Jobs(namespace).Get(context.Background(), h.Name, metav1.GetOptions{})
if err != nil {
return errors.Wrapf(err, "unable to get job for %s", h.Name)
}
pods, err := client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{
LabelSelector: labels.Set(job.Spec.Selector.MatchLabels).String(),
})
if err != nil {
return errors.Wrapf(err, "failed to list pods for job %s", h.Name)
}
for _, pod := range pods.Items {
req := client.CoreV1().Pods(namespace).GetLogs(pod.Name, &v1.PodLogOptions{})
logReader, err := req.Stream(context.Background())
if err != nil {
return errors.Wrapf(err, "unable to get pod logs for %s", pod.Name)
}
fmt.Fprintf(out, "POD LOGS: %s\n", pod.Name)
_, err = io.Copy(out, logReader)
fmt.Fprintln(out)
if err != nil {
return errors.Wrapf(err, "unable to write pod logs for %s", pod.Name)
}
}
case "Pod":
req := client.CoreV1().Pods(namespace).GetLogs(h.Name, &v1.PodLogOptions{})
logReader, err := req.Stream(context.Background())
if err != nil {
return errors.Wrapf(err, "unable to get pod logs for %s", h.Name)
@ -138,8 +177,6 @@ func (r *ReleaseTesting) GetPodLogs(out io.Writer, rel *release.Release) error {
return errors.Wrapf(err, "unable to write pod logs for %s", h.Name)
}
}
}
}
return nil
}

@ -20,6 +20,8 @@ import (
"bytes"
"context"
"fmt"
"io"
"sort"
"strings"
"sync"
"time"
@ -186,6 +188,30 @@ func (u *Upgrade) RunWithContext(ctx context.Context, name string, chart *chart.
return res, nil
}
// 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 (u *Upgrade) GetHookLogs(out io.Writer, rel *release.Release) error {
client, err := u.cfg.KubernetesClientSet()
if err != nil {
return errors.Wrap(err, "unable to get kubernetes client to fetch pod logs")
}
hooksByWeight := append([]*release.Hook{}, rel.Hooks...)
sort.Stable(hookByWeight(hooksByWeight))
for _, h := range hooksByWeight {
for _, e := range h.Events {
if e != release.HookTest {
if err := getHookLogs(out, client, u.Namespace, h); err != nil {
return err
}
}
}
}
return nil
}
// isDryRun returns true if Upgrade is set to run as a DryRun
func (u *Upgrade) isDryRun() bool {
if u.DryRun || u.DryRunOption == "client" || u.DryRunOption == "server" || u.DryRunOption == "true" {

Loading…
Cancel
Save