From 763d46a1ce1e0368b65e19eae1057ac5c294beab Mon Sep 17 00:00:00 2001 From: Sebastian Nickel Date: Tue, 24 Sep 2024 14:52:38 +0200 Subject: [PATCH 1/2] fix versioning info This allows to also have a proper versioning information if no VCS stamping was used or no source code information could be found. --- main.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index c022928..05bc032 100644 --- a/main.go +++ b/main.go @@ -177,7 +177,7 @@ func setupSignalHandler(ctx context.Context, cancel context.CancelFunc) { // checks for variables which would overwrite already existing ones. func kongVariables() (kong.Vars, error) { result := make(kong.Vars) - result["version"] = fmt.Sprintf("%s (commit: %s, date: %s)", version, commit, date) + result["version"] = versionOutput(version, commit, date) result["api_cluster"] = defaultAPICluster appCreateKongVars, err := create.ApplicationKongVars() if err != nil { @@ -190,6 +190,21 @@ func kongVariables() (kong.Vars, error) { return result, nil } +func versionOutput(version, commit, date string) string { + var extra []string + + if commit != "" { + extra = append(extra, "commit: "+commit) + } + if date != "" { + extra = append(extra, "date: "+date) + } + if len(extra) > 0 { + return fmt.Sprintf("%s (%s)", version, strings.Join(extra, ", ")) + } + return version +} + func merge(existing kong.Vars, withs ...kong.Vars) error { for _, with := range withs { for k, v := range with { From ffa014da50f525bff952e736d339a6ecddf41980 Mon Sep 17 00:00:00 2001 From: Sebastian Nickel Date: Wed, 25 Sep 2024 11:12:47 +0200 Subject: [PATCH 2/2] improve log displaying and fix nil panic This improves the live tailing of the logs during application builds by updating the authorization token before every log call. Before we were using the token which was created when starting nctl. It furthermore fixes a `nil` pointer access. --- api/client.go | 2 +- api/log/client.go | 46 ++++++++++++++++++++++++++++++++----------- create/application.go | 13 ++++++++---- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/api/client.go b/api/client.go index ae86376..bc063e5 100644 --- a/api/client.go +++ b/api/client.go @@ -68,7 +68,7 @@ func New(ctx context.Context, apiClusterContext, project string, opts ...ClientO // LogClient sets up a log client connected to the provided address. func LogClient(ctx context.Context, address string, insecure bool) ClientOpt { return func(c *Client) error { - logClient, err := log.NewClient(address, c.Token(ctx), c.Project, insecure) + logClient, err := log.NewClient(address, func(ctx context.Context) string { return c.Token(ctx) }, c.Project, insecure) if err != nil { return fmt.Errorf("unable to create log client: %w", err) } diff --git a/api/log/client.go b/api/log/client.go index edd966a..47ef880 100644 --- a/api/log/client.go +++ b/api/log/client.go @@ -21,7 +21,10 @@ import ( "k8s.io/client-go/util/retry" ) +type tokenFunc func(ctx context.Context) string + type Client struct { + bearerTokenFunc tokenFunc logclient.Client StdOut output.LogOutput } @@ -38,7 +41,7 @@ type Query struct { } // NewClient returns a new log API client. -func NewClient(address, token, orgID string, insecure bool) (*Client, error) { +func NewClient(address string, tokenFunc tokenFunc, orgID string, insecure bool) (*Client, error) { out, err := StdOut("default") if err != nil { return nil, err @@ -50,12 +53,12 @@ func NewClient(address, token, orgID string, insecure bool) (*Client, error) { } return &Client{ - StdOut: out, + bearerTokenFunc: tokenFunc, + StdOut: out, Client: &logclient.DefaultClient{ - Address: address, - BearerToken: token, - OrgID: orgID, - TLSConfig: tls, + Address: address, + OrgID: orgID, + TLSConfig: tls, }, }, nil } @@ -82,8 +85,18 @@ func StdOut(mode string) (output.LogOutput, error) { return out, nil } -// QueryRange queries logs within a specific time range. +func (c *Client) refreshToken(ctx context.Context) { + if c.bearerTokenFunc == nil { + return + } + if defaultClient, is := c.Client.(*logclient.DefaultClient); is { + defaultClient.BearerToken = c.bearerTokenFunc(ctx) + } +} + +// QueryRange queries logs within a specific time range and prints the result. func (c *Client) QueryRange(ctx context.Context, out output.LogOutput, q Query) error { + c.refreshToken(ctx) resp, err := c.Client.QueryRange(q.QueryString, q.Limit, q.Start, q.End, q.Direction, q.Step, q.Interval, q.Quiet) if err != nil { return err @@ -92,6 +105,12 @@ func (c *Client) QueryRange(ctx context.Context, out output.LogOutput, q Query) return printResult(resp.Data.Result, out) } +// QueryRangeResponse queries logs within a specific time range and returns the response. +func (c *Client) QueryRangeResponse(ctx context.Context, q Query) (*loghttp.QueryResponse, error) { + c.refreshToken(ctx) + return c.Client.QueryRange(q.QueryString, q.Limit, q.Start, q.End, q.Direction, q.Step, q.Interval, q.Quiet) +} + // QueryRangeWithRetry queries logs within a specific time range with a retry // in case of an error or not finding any logs. func (c *Client) QueryRangeWithRetry(ctx context.Context, out output.LogOutput, q Query) error { @@ -108,7 +127,7 @@ func (c *Client) QueryRangeWithRetry(ctx context.Context, out output.LogOutput, return true }, func() error { - resp, err := c.Client.QueryRange(q.QueryString, q.Limit, q.Start, q.End, q.Direction, q.Step, q.Interval, q.Quiet) + resp, err := c.QueryRangeResponse(ctx, q) if err != nil { return err } @@ -124,6 +143,12 @@ func (c *Client) QueryRangeWithRetry(ctx context.Context, out output.LogOutput, }) } +// LiveTailQueryConn does a live tailing with a specific query. +func (c *Client) LiveTailQueryConn(ctx context.Context, queryStr string, delayFor time.Duration, limit int, start time.Time, quiet bool) (*websocket.Conn, error) { + c.refreshToken(ctx) + return c.Client.LiveTailQueryConn(queryStr, delayFor, limit, start, quiet) +} + func printResult(value loghttp.ResultValue, out output.LogOutput) error { switch value.Type() { case logqlmodel.ValueTypeStreams: @@ -151,7 +176,7 @@ func printStream(streams loghttp.Streams, out output.LogOutput) { // This has been adapted from https://github.com/grafana/loki/blob/v2.8.2/pkg/logcli/query/tail.go#L22 // as it directly prints out messages using builtin log, which we don't want. func (c *Client) TailQuery(ctx context.Context, delayFor time.Duration, out output.LogOutput, q Query) error { - conn, err := c.LiveTailQueryConn(q.QueryString, delayFor, q.Limit, q.Start, q.Quiet) + conn, err := c.LiveTailQueryConn(ctx, q.QueryString, delayFor, q.Limit, q.Start, q.Quiet) if err != nil { return fmt.Errorf("tailing logs failed: %w", err) } @@ -186,11 +211,10 @@ func (c *Client) TailQuery(ctx context.Context, delayFor time.Duration, out outp }) for backoff.Ongoing() { - conn, err = c.LiveTailQueryConn(q.QueryString, delayFor, q.Limit, lastReceivedTimestamp, q.Quiet) + conn, err = c.LiveTailQueryConn(ctx, q.QueryString, delayFor, q.Limit, lastReceivedTimestamp, q.Quiet) if err == nil { break } - backoff.Wait() } diff --git a/create/application.go b/create/application.go index a0b0020..c0ec747 100644 --- a/create/application.go +++ b/create/application.go @@ -28,6 +28,8 @@ import ( runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" ) +const logPrintTimeout = 10 * time.Second + // note: when adding/changing fields here also make sure to carry it over to // update/application.go. type applicationCmd struct { @@ -188,13 +190,15 @@ func (app *applicationCmd) Run(ctx context.Context, client *api.Client) error { waitForBuildFinish(appWaitCtx, newApp, client.Log), waitForRelease(newApp), ); err != nil { + printCtx, cancel := context.WithTimeout(context.Background(), logPrintTimeout) + defer cancel() if buildErr, ok := err.(buildError); ok { - if err := buildErr.printMessage(appWaitCtx, client); err != nil { + if err := buildErr.printMessage(printCtx, client); err != nil { return fmt.Errorf("%s: %w", buildErr, err) } } if releaseErr, ok := err.(releaseError); ok { - if err := releaseErr.printMessage(appWaitCtx, client); err != nil { + if err := releaseErr.printMessage(printCtx, client); err != nil { return fmt.Errorf("%s: %w", releaseErr, err) } } @@ -437,8 +441,9 @@ type releaseError struct { } func (r releaseError) Error() string { - if r.release.Status.AtProvider.DeployJobStatus.Status == "" { - switch r.release.Status.AtProvider.DeployJobStatus.Reason { + deployJobStatus := r.release.Status.AtProvider.DeployJobStatus + if deployJobStatus != nil && deployJobStatus.Status == "" { + switch deployJobStatus.Reason { case apps.DeployJobProcessReasonBackoff: return "deploy job has failed after all retries." case apps.DeployJobProcessReasonTimeout: