-
Notifications
You must be signed in to change notification settings - Fork 26
/
logs.go
131 lines (110 loc) · 3.44 KB
/
logs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package buildrun
import (
"context"
"fmt"
"strings"
"time"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/cli-runtime/pkg/genericclioptions"
buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1"
"github.com/spf13/cobra"
"github.com/shipwright-io/cli/pkg/shp/cmd/follower"
"github.com/shipwright-io/cli/pkg/shp/cmd/runner"
"github.com/shipwright-io/cli/pkg/shp/params"
"github.com/shipwright-io/cli/pkg/shp/util"
)
// LogsCommand contains data input from user for logs sub-command
type LogsCommand struct {
cmd *cobra.Command
name string
follow bool
follower *follower.Follower
}
func logsCmd() runner.SubCommand {
cmd := &cobra.Command{
Use: "logs <name>",
Short: "See BuildRun log output",
Args: cobra.ExactArgs(1),
}
logCommand := &LogsCommand{
cmd: cmd,
}
cmd.Flags().BoolVarP(&logCommand.follow, "follow", "F", logCommand.follow, "Follow the log of a buildrun until it completes or fails.")
return logCommand
}
// Cmd returns cobra command object
func (c *LogsCommand) Cmd() *cobra.Command {
return c.cmd
}
// Complete fills in data provided by user
func (c *LogsCommand) Complete(params *params.Params, ioStreams *genericclioptions.IOStreams, args []string) error {
c.name = args[0]
if !c.follow {
return nil
}
br := types.NamespacedName{
Namespace: params.Namespace(),
Name: c.name,
}
var err error
c.follower, err = params.NewFollower(c.Cmd().Context(), br, ioStreams)
return err
}
// Validate validates data input by user
func (c *LogsCommand) Validate() error {
return nil
}
// Run executes logs sub-command logic
func (c *LogsCommand) Run(params *params.Params, ioStreams *genericclioptions.IOStreams) error {
clientset, err := params.ClientSet()
if err != nil {
return err
}
lo := v1.ListOptions{
LabelSelector: fmt.Sprintf("%v=%v", buildv1alpha1.LabelBuildRun, c.name),
}
// first see if pod is already done; if so, even if we have follow == true, just do the normal path;
// we don't employ a pod watch here since the buildrun may already be complete before 'shp buildrun logs -F'
// is invoked.
justGetLogs := false
var pods *corev1.PodList
err = wait.PollUntilContextTimeout(c.cmd.Context(), 1*time.Second, 10*time.Second, true, func(ctx context.Context) (done bool, err error) {
if pods, err = clientset.CoreV1().Pods(params.Namespace()).List(ctx, lo); err != nil {
fmt.Fprintf(ioStreams.ErrOut, "error listing Pods for BuildRun %q: %s\n", c.name, err.Error())
return false, nil
}
if len(pods.Items) == 0 {
fmt.Fprintf(ioStreams.ErrOut, "no builder pod found for BuildRun %q\n", c.name)
return false, nil
}
return true, nil
})
if err != nil {
return err
}
pod := pods.Items[0]
phase := pod.Status.Phase
if phase == corev1.PodFailed || phase == corev1.PodSucceeded {
justGetLogs = true
}
if !c.follow || justGetLogs {
fmt.Fprintf(ioStreams.Out, "Obtaining logs for BuildRun %q\n\n", c.name)
var b strings.Builder
containers := append(pod.Spec.InitContainers, pod.Spec.Containers...)
for _, container := range containers {
logs, err := util.GetPodLogs(c.cmd.Context(), clientset, pod, container.Name)
if err != nil {
return err
}
fmt.Fprintf(&b, "*** Pod %q, container %q: ***\n\n", pod.Name, container.Name)
fmt.Fprintln(&b, logs)
}
fmt.Fprintln(ioStreams.Out, b.String())
return nil
}
_, err = c.follower.Start(lo)
return err
}