Skip to content

Commit

Permalink
rpk: add container error log to start
Browse files Browse the repository at this point in the history
This also add the container error logs to the
startCluster method.
  • Loading branch information
r-vasquez committed Apr 11, 2024
1 parent 7494186 commit d0d52c5
Showing 1 changed file with 57 additions and 33 deletions.
90 changes: 57 additions & 33 deletions src/go/rpk/pkg/cli/container/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ package container

import (
"bufio"
"bytes"
"context"
"errors"
"fmt"
Expand All @@ -24,6 +25,8 @@ import (

"github.com/avast/retry-go"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/stdcopy"
"github.com/redpanda-data/redpanda/src/go/rpk/pkg/cli/container/common"
"github.com/redpanda-data/redpanda/src/go/rpk/pkg/config"
vnet "github.com/redpanda-data/redpanda/src/go/rpk/pkg/net"
Expand Down Expand Up @@ -281,7 +284,15 @@ func startCluster(
}
err = waitForCluster(check(nodes), retries)
if err != nil {
return false, err
state, sErr := common.GetState(c, nodes[0].id)
if sErr != nil {
return false, fmt.Errorf("%v\nunable to get Docker container logs: %v", err, sErr)
}
errStr, cErr := getContainerErr(state, c)
if cErr != nil {
return false, fmt.Errorf("%v\nunable to get Docker container logs: %v", err, cErr)
}
return false, fmt.Errorf("%v\n\nErrors reported from the Docker container:\n\n%v", err, errStr)
}

fmt.Println("Cluster started!")
Expand Down Expand Up @@ -337,39 +348,11 @@ func restartCluster(
}
err = waitForCluster(check(nodes), retries)
if err != nil {
// Attempt to fetch the latest stderr output from the first
// Redpanda node. It may reveal reasons for failing to start.
ctx, _ := common.DefaultCtx()
state := states[0]

json, errInspect := c.ContainerInspect(ctx, state.ContainerID)
if errInspect != nil {
return nil, fmt.Errorf("%v\n%v", err, errInspect)
errStr, cErr := getContainerErr(states[0], c)
if cErr != nil {
return nil, fmt.Errorf("%v\nunable to get Docker container logs: %v", err, cErr)
}

reader, errLogs := c.ContainerLogs(
ctx,
state.ContainerID,
types.ContainerLogsOptions{
ShowStdout: false,
ShowStderr: true,
Since: json.State.StartedAt,
},
)
if errLogs != nil {
return nil, fmt.Errorf("%v\nCould not get container logs: %v", err, errLogs)
}

scanner := bufio.NewScanner(reader)
errStr := ""
for scanner.Scan() {
errStr += scanner.Text() + "\n"
}
return nil, fmt.Errorf(
"%v\nErrors reported from the Docker container:\n%v",
err,
errors.New(errStr),
)
return nil, fmt.Errorf("%v\n\nErrors reported from the Docker container:\n%v", err, errStr)
}
return nodes, nil
}
Expand Down Expand Up @@ -510,3 +493,44 @@ func nodeAddr(port uint) string {
port,
)
}

// getContainerErr attempts to fetch the latest stderr output from the first
// Redpanda node. It may reveal reasons for failing to start.
func getContainerErr(state *common.NodeState, c common.Client) (string, error) {
ctx, _ := common.DefaultCtx()

json, err := c.ContainerInspect(ctx, state.ContainerID)
if err != nil {
return "", fmt.Errorf("could not inspect container: %v", err)
}

reader, err := c.ContainerLogs(
ctx,
state.ContainerID,
container.LogsOptions{
ShowStdout: false,
ShowStderr: true,
Since: json.State.StartedAt,
},
)
if err != nil {
return "", fmt.Errorf("could not get container logs: %v", err)
}

// Docker logs over the wire are multiplexed using stdcopy package. To
// demux this stream we need to use stdcopy.StdCopy. See:
// https://github.com/moby/moby/issues/32794#issuecomment-297151440
bErr := bytes.NewBufferString("")
_, err = stdcopy.StdCopy(bErr, bErr, reader)
if err != nil {
return "", fmt.Errorf("unable to read docker logs: %v", err)
}

scanner := bufio.NewScanner(bErr)
var errStr string
for scanner.Scan() {
errStr += scanner.Text() + "\n"
}

return errStr, nil
}

0 comments on commit d0d52c5

Please sign in to comment.