diff --git a/go.mod b/go.mod index e058de80c..062aafdad 100644 --- a/go.mod +++ b/go.mod @@ -76,7 +76,7 @@ require ( k8s.io/apimachinery v0.29.3 k8s.io/apiserver v0.29.3 oras.land/oras-go/v2 v2.5.0 - sdk.kraft.cloud v0.5.5-0.20240408130935-44faa2c974b3 + sdk.kraft.cloud v0.5.5-0.20240410102038-8d0f0333b17a sigs.k8s.io/kustomize/kyaml v0.14.3 ) diff --git a/go.sum b/go.sum index ba6bb6aa6..eeccbcd88 100644 --- a/go.sum +++ b/go.sum @@ -1677,8 +1677,8 @@ oras.land/oras-go/v2 v2.5.0/go.mod h1:z4eisnLP530vwIOUOJeBIj0aGI0L1C3d53atvCBqZH rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sdk.kraft.cloud v0.5.5-0.20240408130935-44faa2c974b3 h1:WNGjGRijO9vHa2DOVqOAJXqL+RBhsdkQAG/Jb9JmQnk= -sdk.kraft.cloud v0.5.5-0.20240408130935-44faa2c974b3/go.mod h1:u88mmv6PoEASnMLNkyYgrMCzJ4tkMGurV8ZMvXA9a2I= +sdk.kraft.cloud v0.5.5-0.20240410102038-8d0f0333b17a h1:23i4O5zQRjwqpFslVVdgcR3Kj42Qw7XGfGHPbufoqFs= +sdk.kraft.cloud v0.5.5-0.20240410102038-8d0f0333b17a/go.mod h1:u88mmv6PoEASnMLNkyYgrMCzJ4tkMGurV8ZMvXA9a2I= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 h1:TgtAeesdhpm2SGwkQasmbeqDo8th5wOBA5h/AjTKA4I= diff --git a/internal/cli/kraft/cloud/instance/logs/logs.go b/internal/cli/kraft/cloud/instance/logs/logs.go index 095ad2822..5c7a077c6 100644 --- a/internal/cli/kraft/cloud/instance/logs/logs.go +++ b/internal/cli/kraft/cloud/instance/logs/logs.go @@ -6,29 +6,18 @@ package logs import ( "context" - "encoding/base64" - "errors" "fmt" - "strings" "time" "github.com/MakeNowJust/heredoc" "github.com/spf13/cobra" kraftcloud "sdk.kraft.cloud" - kcinstances "sdk.kraft.cloud/instances" "kraftkit.sh/cmdfactory" "kraftkit.sh/config" "kraftkit.sh/internal/cli/kraft/cloud/utils" "kraftkit.sh/iostreams" - "kraftkit.sh/log" -) - -const ( - defaultPageSize = 4096 - maxPageSize = defaultPageSize*4 - 1 - maxPossibleBytes = 1024 * 1024 * 1024 ) type LogOptions struct { @@ -91,37 +80,13 @@ func (opts *LogOptions) Pre(cmd *cobra.Command, _ []string) error { } if opts.Tail < -1 { - return fmt.Errorf("invalid value for --tail: %d, should be -1, or positive", opts.Tail) - } - - if opts.Follow && opts.Tail == -1 { - opts.Tail = 100 + return fmt.Errorf("invalid value for --tail: %d, should be -1 for all logs, or positive for length of truncated logs", opts.Tail) } return nil } -func (opts *LogOptions) logsFetchDecode(ctx context.Context, client kcinstances.InstancesService, image string, offset, limit int) ([]byte, *kcinstances.LogResponseItem, error) { - logResp, err := client.WithMetro(opts.metro).Log(ctx, image, offset, limit) - if err != nil { - return nil, nil, fmt.Errorf("could not retrieve logs: %w", err) - } - log, err := logResp.FirstOrErr() - if err != nil { - return nil, nil, fmt.Errorf("could not retrieve logs: %w", err) - } - - outputPart, err := base64.StdEncoding.DecodeString(log.Output) - if err != nil { - return nil, nil, fmt.Errorf("decoding base64 console output: %w", err) - } - - return outputPart, log, nil -} - func (opts *LogOptions) Run(ctx context.Context, args []string) error { - var offset, limit int - auth, err := config.GetKraftCloudAuthConfig(ctx, opts.token) if err != nil { return fmt.Errorf("could not retrieve credentials: %w", err) @@ -131,103 +96,21 @@ func (opts *LogOptions) Run(ctx context.Context, args []string) error { kraftcloud.WithToken(config.GetKraftCloudTokenAuthConfig(*auth)), ) - if opts.Follow { - offset = -defaultPageSize - limit = maxPageSize - - for { - output, resp, err := opts.logsFetchDecode(ctx, client, args[0], offset, limit) - if err != nil { - if errors.Is(err, context.Canceled) { - return nil - } - return err - } - - // Split the output by line and print each line separately to - // be able to limit the output to the last N lines. - // Truncate the last line if it's not a full line. - if len(output) > 0 { - split := strings.Split(string(output), "\n") - linesToSkip := len(split) - opts.Tail - for i, line := range split { - if i < linesToSkip { - continue - } - - if i == len(split)-1 && output[len(output)-1] != '\n' { - offset = resp.Range.End - len(line) - } else { - if i == len(split)-1 { - offset = resp.Range.End - } - fmt.Fprintf(iostreams.G(ctx).Out, "%s\n", line) - } - } - } - - time.Sleep(500 * time.Millisecond) - } + logChan, errChan, err := client.TailLogs(ctx, args[0], opts.Follow, opts.Tail, 500*time.Millisecond) + if err != nil { + return fmt.Errorf("initializing log tailing: %w", err) } - var output []byte - if opts.Tail >= 0 { - lines := 0 - for i := 1; lines < opts.Tail; i++ { - offset = i * -defaultPageSize - limit = defaultPageSize - - outputPart, resp, err := opts.logsFetchDecode(ctx, client, args[0], offset, limit) - if err != nil { - return err - } - - outputPart = append(outputPart, output...) - output = outputPart - - if resp.Range.Start == resp.Available.Start { - break + for { + select { + case <-ctx.Done(): + return nil + case err := <-errChan: + return err + case line, ok := <-logChan: + if ok { + fmt.Fprintf(iostreams.G(ctx).Out, "%s\n", line) } - - lines += strings.Count(string(outputPart), "\n") - } - - split := strings.Split(string(output), "\n") - start := len(split) - opts.Tail - if start < 0 { - start = 0 } - for i := start; i < len(split); i++ { - fmt.Fprintf(iostreams.G(ctx).Out, "%s\n", split[i]) - } - } else { - // The same as above, but fetch the max possible amount of logs. - // Stop only when there are no more logs to fetch. - for i := 4; ; i = i + 4 { - offset = i * -defaultPageSize - limit = maxPageSize - - outputPart, resp, err := opts.logsFetchDecode(ctx, client, args[0], offset, limit) - if err != nil { - return err - } - - outputPart = append(outputPart, output...) - output = outputPart - - if resp.Range.Start == resp.Available.Start { - break - } - - if len(output) > maxPossibleBytes { - log.G(ctx).Warnf("The maximum amount of logs has been reached. Stopping.") - fmt.Fprintf(iostreams.G(ctx).Out, "%s\n", output) - break - } - } - - fmt.Fprintf(iostreams.G(ctx).Out, "%s\n", output) } - - return nil }