From 27e6c117d9b03046fd060d065ff6e0a456665283 Mon Sep 17 00:00:00 2001 From: Maksym Pavlenko Date: Wed, 2 Oct 2024 10:59:30 -0700 Subject: [PATCH] Move HTTP debug code to pkg Signed-off-by: Maksym Pavlenko --- cmd/ctr/commands/content/fetch.go | 3 +- cmd/ctr/commands/images/push.go | 3 +- cmd/ctr/commands/resolver.go | 69 ++---------------------- pkg/httpdbg/debug.go | 87 +++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 67 deletions(-) create mode 100644 pkg/httpdbg/debug.go diff --git a/cmd/ctr/commands/content/fetch.go b/cmd/ctr/commands/content/fetch.go index 62d9bdc6be..04dbcd1253 100644 --- a/cmd/ctr/commands/content/fetch.go +++ b/cmd/ctr/commands/content/fetch.go @@ -31,6 +31,7 @@ import ( "github.com/containerd/containerd/v2/core/content" "github.com/containerd/containerd/v2/core/images" "github.com/containerd/containerd/v2/core/remotes" + "github.com/containerd/containerd/v2/pkg/httpdbg" "github.com/containerd/containerd/v2/pkg/progress" "github.com/containerd/errdefs" "github.com/containerd/log" @@ -168,7 +169,7 @@ func Fetch(ctx context.Context, client *containerd.Client, ref string, config *F ongoing := NewJobs(ref) if config.TraceHTTP { - ctx = httptrace.WithClientTrace(ctx, commands.NewDebugClientTrace(ctx)) + ctx = httptrace.WithClientTrace(ctx, httpdbg.NewDebugClientTrace(ctx)) } pctx, stopProgress := context.WithCancel(ctx) diff --git a/cmd/ctr/commands/images/push.go b/cmd/ctr/commands/images/push.go index 25b2cd6a4b..4c904b5948 100644 --- a/cmd/ctr/commands/images/push.go +++ b/cmd/ctr/commands/images/push.go @@ -35,6 +35,7 @@ import ( "github.com/containerd/containerd/v2/core/transfer" "github.com/containerd/containerd/v2/core/transfer/image" "github.com/containerd/containerd/v2/core/transfer/registry" + "github.com/containerd/containerd/v2/pkg/httpdbg" "github.com/containerd/containerd/v2/pkg/progress" "github.com/containerd/log" "github.com/containerd/platforms" @@ -176,7 +177,7 @@ var pushCommand = &cli.Command{ } if cliContext.Bool("http-trace") { - ctx = httptrace.WithClientTrace(ctx, commands.NewDebugClientTrace(ctx)) + ctx = httptrace.WithClientTrace(ctx, httpdbg.NewDebugClientTrace(ctx)) } resolver, err := commands.GetResolver(ctx, cliContext) if err != nil { diff --git a/cmd/ctr/commands/resolver.go b/cmd/ctr/commands/resolver.go index befeb46ef4..6ed73b2015 100644 --- a/cmd/ctr/commands/resolver.go +++ b/cmd/ctr/commands/resolver.go @@ -23,10 +23,7 @@ import ( "crypto/x509" "errors" "fmt" - "io" "net/http" - "net/http/httptrace" - "net/http/httputil" "os" "strings" @@ -35,6 +32,7 @@ import ( "github.com/containerd/containerd/v2/core/remotes/docker" "github.com/containerd/containerd/v2/core/remotes/docker/config" "github.com/containerd/containerd/v2/core/transfer/registry" + "github.com/containerd/containerd/v2/pkg/httpdbg" "github.com/containerd/log" "github.com/urfave/cli/v2" ) @@ -104,9 +102,9 @@ func GetResolver(ctx context.Context, cliContext *cli.Context) (remotes.Resolver if cliContext.Bool("http-dump") { hostOptions.UpdateClient = func(client *http.Client) error { - client.Transport = &DebugTransport{ - transport: client.Transport, - writer: log.G(ctx).Writer(), + client.Transport = &httpdbg.DebugTransport{ + Transport: client.Transport, + Writer: log.G(ctx).Writer(), } return nil } @@ -157,65 +155,6 @@ func resolverDefaultTLS(cliContext *cli.Context) (*tls.Config, error) { return tlsConfig, nil } -// DebugTransport wraps the underlying http.RoundTripper interface and dumps all requests/responses to the writer. -type DebugTransport struct { - transport http.RoundTripper - writer io.Writer -} - -// RoundTrip dumps request/responses and executes the request using the underlying transport. -func (t DebugTransport) RoundTrip(req *http.Request) (*http.Response, error) { - in, err := httputil.DumpRequestOut(req, true) - if err != nil { - return nil, fmt.Errorf("failed to dump request: %w", err) - } - - if _, err := t.writer.Write(in); err != nil { - return nil, err - } - - resp, err := t.transport.RoundTrip(req) - if err != nil { - return nil, err - } - - out, err := httputil.DumpResponse(resp, true) - if err != nil { - return nil, fmt.Errorf("failed to dump response: %w", err) - } - - if _, err := t.writer.Write(out); err != nil { - return nil, err - } - - return resp, err -} - -// NewDebugClientTrace returns a Go http trace client predefined to write DNS and connection -// information to the log. This is used via the --http-trace flag on push and pull operations in ctr. -func NewDebugClientTrace(ctx context.Context) *httptrace.ClientTrace { - return &httptrace.ClientTrace{ - DNSStart: func(dnsInfo httptrace.DNSStartInfo) { - log.G(ctx).WithField("host", dnsInfo.Host).Debugf("DNS lookup") - }, - DNSDone: func(dnsInfo httptrace.DNSDoneInfo) { - if dnsInfo.Err != nil { - log.G(ctx).WithField("lookup_err", dnsInfo.Err).Debugf("DNS lookup error") - } else { - log.G(ctx).WithField("result", dnsInfo.Addrs[0].String()).WithField("coalesced", dnsInfo.Coalesced).Debugf("DNS lookup complete") - } - }, - GotConn: func(connInfo httptrace.GotConnInfo) { - remoteAddr := "" - if addr := connInfo.Conn.RemoteAddr(); addr != nil { - remoteAddr = addr.String() - } - - log.G(ctx).WithField("reused", connInfo.Reused).WithField("remote_addr", remoteAddr).Debugf("Connection successful") - }, - } -} - type staticCredentials struct { ref string username string diff --git a/pkg/httpdbg/debug.go b/pkg/httpdbg/debug.go new file mode 100644 index 0000000000..a56c488b09 --- /dev/null +++ b/pkg/httpdbg/debug.go @@ -0,0 +1,87 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package httpdbg + +import ( + "context" + "fmt" + "io" + "net/http" + "net/http/httptrace" + "net/http/httputil" + + "github.com/containerd/log" +) + +// DebugTransport wraps the underlying http.RoundTripper interface and dumps all requests/responses to the writer. +type DebugTransport struct { + Transport http.RoundTripper + Writer io.Writer +} + +// RoundTrip dumps request/responses and executes the request using the underlying transport. +func (t DebugTransport) RoundTrip(req *http.Request) (*http.Response, error) { + in, err := httputil.DumpRequestOut(req, true) + if err != nil { + return nil, fmt.Errorf("failed to dump request: %w", err) + } + + if _, err := t.Writer.Write(in); err != nil { + return nil, err + } + + resp, err := t.Transport.RoundTrip(req) + if err != nil { + return nil, err + } + + out, err := httputil.DumpResponse(resp, true) + if err != nil { + return nil, fmt.Errorf("failed to dump response: %w", err) + } + + if _, err := t.Writer.Write(out); err != nil { + return nil, err + } + + return resp, err +} + +// NewDebugClientTrace returns a Go http trace client predefined to write DNS and connection +// information to the log. This is used via the --http-trace flag on push and pull operations in ctr. +func NewDebugClientTrace(ctx context.Context) *httptrace.ClientTrace { + return &httptrace.ClientTrace{ + DNSStart: func(dnsInfo httptrace.DNSStartInfo) { + log.G(ctx).WithField("host", dnsInfo.Host).Debugf("DNS lookup") + }, + DNSDone: func(dnsInfo httptrace.DNSDoneInfo) { + if dnsInfo.Err != nil { + log.G(ctx).WithField("lookup_err", dnsInfo.Err).Debugf("DNS lookup error") + } else { + log.G(ctx).WithField("result", dnsInfo.Addrs[0].String()).WithField("coalesced", dnsInfo.Coalesced).Debugf("DNS lookup complete") + } + }, + GotConn: func(connInfo httptrace.GotConnInfo) { + remoteAddr := "" + if addr := connInfo.Conn.RemoteAddr(); addr != nil { + remoteAddr = addr.String() + } + + log.G(ctx).WithField("reused", connInfo.Reused).WithField("remote_addr", remoteAddr).Debugf("Connection successful") + }, + } +}