Skip to content

Commit bb3457d

Browse files
authored
enhance logs functionality to handle build stage log (#48)
* enhance logs functionality to handle build stage log Signed-off-by: Alex Ji <jilichao@aliyun.com>
1 parent a85a24f commit bb3457d

File tree

3 files changed

+89
-17
lines changed

3 files changed

+89
-17
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010
github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852
1111
github.com/openfunction v0.0.0-00010101000000-000000000000
1212
github.com/pkg/errors v0.9.1
13+
github.com/shipwright-io/build v0.6.0
1314
github.com/spf13/cobra v1.2.1
1415
github.com/spf13/pflag v1.0.5
1516
gopkg.in/yaml.v2 v2.4.0

go.sum

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb0
155155
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
156156
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
157157
github.com/OneOfOne/xxhash v1.2.7/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
158-
github.com/OpenFunction/OpenFunction v0.6.0 h1:VfIqhLBz3I9DBheWBjKuFHZ2L31NdDvf0ZcAkT+P+70=
158+
github.com/OpenFunction/OpenFunction v0.6.0 h1:BZZCgr4s6OFadPRhrO+vRKpo4BHznknZMMOHQc/I3hs=
159159
github.com/OpenFunction/OpenFunction v0.6.0/go.mod h1:7Ida4Kxst2Y+EnbIh/OELB22JXlJO81+PoXWJnB0sSw=
160160
github.com/ProtonMail/go-crypto v0.0.0-20210329181949-3900d675f39b/go.mod h1:HTM9X7e9oLwn7RiqLG0UVwVRJenLs3wN+tQ0NPAfwMQ=
161161
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
@@ -1338,6 +1338,7 @@ github.com/sendgrid/sendgrid-go v3.5.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw
13381338
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
13391339
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
13401340
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
1341+
github.com/shipwright-io/build v0.6.0 h1:E8jBhnXOUIP/Omyg/sB5StnfTVmj/cJ8nEPcsUeYdrg=
13411342
github.com/shipwright-io/build v0.6.0/go.mod h1:OllxAXgx6J4DjbiTrs+/E8lGHzMfUvf7/qzdRhvzaxg=
13421343
github.com/shirou/gopsutil v3.20.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
13431344
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=

pkg/cmd/subcommand/logs.go

Lines changed: 86 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ import (
2525
"github.com/OpenFunction/cli/pkg/cmd/util"
2626
cc "github.com/OpenFunction/cli/pkg/cmd/util/client"
2727
client "github.com/openfunction/pkg/client/clientset/versioned"
28+
swclient "github.com/shipwright-io/build/pkg/client/clientset/versioned"
2829
"github.com/spf13/cobra"
2930
corev1 "k8s.io/api/core/v1"
31+
k8serrors "k8s.io/apimachinery/pkg/api/errors"
3032
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3133
"k8s.io/cli-runtime/pkg/genericclioptions"
3234
k8s "k8s.io/client-go/kubernetes"
@@ -44,29 +46,29 @@ type Logs struct {
4446

4547
functionClient client.Interface
4648
clientSet *k8s.Clientset
49+
swClient swclient.Interface
4750
}
4851

4952
// NewCmdLogs builds the `logs` sub command
5053
func NewCmdLogs(cf *genericclioptions.ConfigFlags, ioStreams genericclioptions.IOStreams) *cobra.Command {
5154

5255
l := &Logs{
53-
IOStreams: &ioStreams,
54-
containerName: "function",
56+
IOStreams: &ioStreams,
5557
}
5658

5759
cmd := &cobra.Command{
5860
Use: `logs [OPTIONS] FUNCTION_NAME [CONTAINER_NAME]`,
5961
DisableFlagsInUseLine: true,
60-
Short: "Get the logs from the serving pods created by the function",
61-
Long: `Get the logs from the serving pods created by the function`,
62+
Short: "Get the logs from the build and serving pods created by the function",
63+
Long: `Get the logs from the build and serving pods created by the function`,
6264
Example: `
63-
# Get tht logs from the 'function' container in the serving pods created by the function whose name is 'demo-function'
65+
# Get tht logs from all container in the build and serving pods created by the function whose name is 'demo-function'
6466
ofn logs demo-function
6567
66-
# Get tht logs from the 'extra' container (a container whose name is not 'function') in the serving pods created by the function whose name is 'demo-function'
68+
# Get tht logs from the 'extra' container (a container whose name is not 'function') in the build or serving pods created by the function whose name is 'demo-function'
6769
ofn logs demo-function extra
6870
69-
# Begin streaming the logs from the 'function' container in the serving pods created by the function whose name is 'demo-function'
71+
# Begin streaming the logs from the 'function' container in the build and serving pods created by the function whose name is 'demo-function'
7072
ofn logs -f demo-function
7173
`,
7274
PreRunE: func(cmd *cobra.Command, args []string) (err error) {
@@ -91,6 +93,7 @@ func (l *Logs) preRun(cf *genericclioptions.ConfigFlags, args []string) error {
9193
return err
9294
}
9395
l.functionClient = client.NewForConfigOrDie(config)
96+
l.swClient = swclient.NewForConfigOrDie(config)
9497

9598
if cf.Namespace != nil && *(cf.Namespace) != "" {
9699
l.namespace = *(cf.Namespace)
@@ -116,26 +119,93 @@ func (l *Logs) run() error {
116119
if err != nil {
117120
return err
118121
}
119-
if f.Status.Serving == nil {
120-
return nil
122+
123+
// Build stage
124+
if f.Status.Build != nil {
125+
builderRef := f.Status.Build.ResourceRef
126+
127+
// get openfunction builder ref
128+
builder, err := l.functionClient.CoreV1beta1().Builders(f.Namespace).Get(ctx, builderRef, metav1.GetOptions{})
129+
if err != nil {
130+
statusError, ok := err.(*k8serrors.StatusError)
131+
// builder has been cleaned up
132+
if !ok || statusError.Status().Code != 404 {
133+
return err
134+
}
135+
}
136+
137+
// get shipwright builder-buildrun
138+
swbuildrunRef := builder.Status.ResourceRef["shipwright.io/buildRun"]
139+
if swbuildrunRef != "" {
140+
swBuildRun, err := l.swClient.ShipwrightV1alpha1().BuildRuns(f.Namespace).Get(ctx, swbuildrunRef, metav1.GetOptions{})
141+
if err != nil {
142+
statusError, ok := err.(*k8serrors.StatusError)
143+
// buildrun has been cleaned up
144+
if !ok || statusError.Status().Code != 404 {
145+
return err
146+
}
147+
}
148+
err = l.logsForPods(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("buildrun.shipwright.io/name=%s", swBuildRun.Name)})
149+
if err != nil {
150+
return err
151+
}
152+
}
153+
154+
}
155+
156+
// Serving stage
157+
if f.Status.Serving != nil {
158+
serving := f.Status.Serving.ResourceRef
159+
160+
if l.containerName == "" {
161+
l.containerName = "function"
162+
}
163+
err := l.logsForPods(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("openfunction.io/serving=%s", serving)})
164+
if err != nil {
165+
return err
166+
}
121167
}
122-
serving := f.Status.Serving.ResourceRef
123-
listOpt := metav1.ListOptions{LabelSelector: fmt.Sprintf("openfunction.io/serving=%s", serving)}
168+
169+
return nil
170+
}
171+
172+
func (l *Logs) logsForPods(ctx context.Context, listOpt metav1.ListOptions) error {
173+
// retrieves pod list according to the options
124174
podInterface := l.clientSet.CoreV1().Pods(l.namespace)
175+
readerList := make([]io.Reader, 0, 5)
125176
podList, err := podInterface.List(ctx, listOpt)
126177
if err != nil {
127178
return err
128179
}
129-
readerList := make([]io.Reader, 0, len(podList.Items))
180+
181+
// append stream of each container
130182
for _, pod := range podList.Items {
131-
logReader, err := podInterface.GetLogs(pod.Name, &corev1.PodLogOptions{Follow: l.Follow, Container: l.containerName}).Stream(ctx)
132-
defer logReader.Close()
183+
var logReader io.ReadCloser
184+
if l.containerName != "" {
185+
logReader, err = podInterface.GetLogs(pod.Name, &corev1.PodLogOptions{Follow: l.Follow, Container: l.containerName}).Stream(ctx)
186+
if err != nil {
187+
return err
188+
}
189+
defer logReader.Close()
190+
readerList = append(readerList, logReader)
191+
} else {
192+
for _, container := range pod.Spec.Containers {
193+
logReader, err = podInterface.GetLogs(pod.Name, &corev1.PodLogOptions{Follow: l.Follow, Container: container.Name}).Stream(ctx)
194+
if err != nil {
195+
return err
196+
}
197+
198+
defer logReader.Close()
199+
readerList = append(readerList, logReader)
200+
}
201+
}
133202
if err != nil {
134203
return err
135204
}
136-
readerList = append(readerList, logReader)
137205
}
206+
138207
reader := io.MultiReader(readerList...)
139-
_, err = io.Copy(l.IOStreams.Out, reader)
208+
io.Copy(l.IOStreams.Out, reader)
209+
140210
return err
141211
}

0 commit comments

Comments
 (0)