pull/31108/merge
Sowmith Kuppa 1 month ago committed by GitHub
commit c723b39bd9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -20,6 +20,9 @@ import (
"fmt"
"io"
"io/fs"
"log/slog"
"net/http"
"net/http/httputil"
"net/url"
"os"
"path/filepath"
@ -68,12 +71,51 @@ type ChartDownloader struct {
// Getter collection for the operation
Getters getter.Providers
// Options provide parameters to be passed along to the Getter being initialized.
Options []getter.Option
Options []getter.Option
// Debug bool //Added to capture the --debug flag
RegistryClient *registry.Client
RepositoryConfig string
RepositoryCache string
}
type debugTransport struct {
*http.Transport
out io.Writer
}
func (t *debugTransport) RoundTrip(req *http.Request) (*http.Response, error) {
debug := os.Getenv("HELM_DEBUG") == "true"
if debug {
slog.Debug("HTTP request", "url", req.URL.String())
// Log the request
reqDump, err := httputil.DumpRequestOut(req, false)
if err == nil {
slog.Debug("HTTP request dump", "dump", string(reqDump))
}
}
// Perform the request
resp, err := t.Transport.RoundTrip(req)
if err != nil {
if debug {
slog.Debug("HTTP request failed", "error", err)
}
return nil, err
}
// Log the response
if debug {
respDump, err := httputil.DumpResponse(resp, false)
if err == nil {
slog.Debug("HTTP response dump", "dump", string(respDump))
}
if resp.StatusCode >= 300 && resp.StatusCode < 400 {
location := resp.Header["Location"]
slog.Debug("HTTP redirect", "location", location)
}
}
return resp, err
}
// DownloadTo retrieves a chart. Depending on the settings, it may also download a provenance file.
//
// If Verify is set to VerifyNever, the verification will be nil.
@ -86,20 +128,43 @@ type ChartDownloader struct {
// Returns a string path to the location where the file was downloaded and a verification
// (if provenance was verified), or an error if something bad happened.
func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *provenance.Verification, error) {
debug := os.Getenv("HELM_DEBUG") == "true"
// If debug is enabled, wrap the getter's HTTP client with a debug transport
if debug {
dt := &debugTransport{
Transport: http.DefaultTransport.(*http.Transport).Clone(),
out: c.Out,
}
dt.DisableKeepAlives = true
c.Options = append(c.Options, getter.WithClient(&http.Client{
Transport: dt,
CheckRedirect: func(req *http.Request, _ []*http.Request) error {
slog.Debug("Following redirect", "url", req.URL.String())
return nil
},
}))
}
c.Options = append(c.Options, getter.WithAcceptHeader("application/gzip,application/octet-stream"))
u, err := c.ResolveChartVersion(ref, version)
if err != nil {
slog.Debug("Failed to resolve chart version", "error", err)
return "", nil, err
}
slog.Debug("Resolved chart URL", "url", u.String())
g, err := c.Getters.ByScheme(u.Scheme)
if err != nil {
slog.Debug("Failed to get getter for scheme", "scheme", u.Scheme, "error", err)
return "", nil, err
}
c.Options = append(c.Options, getter.WithAcceptHeader("application/gzip,application/octet-stream"))
slog.Debug("Using getter for scheme", "scheme", u.Scheme)
data, err := g.Get(u.String(), c.Options...)
if err != nil {
slog.Debug("Failed to fetch chart", "error", err)
return "", nil, err
}
@ -117,6 +182,21 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven
// If provenance is requested, verify it.
ver := &provenance.Verification{}
if c.Verify > VerifyNever {
// If debug is enabled, use the same debug transport for provenance file
if debug {
dt := &debugTransport{
Transport: http.DefaultTransport.(*http.Transport).Clone(),
out: c.Out,
}
dt.DisableKeepAlives = true
c.Options = append(c.Options, getter.WithClient(&http.Client{
Transport: dt,
CheckRedirect: func(req *http.Request, _ []*http.Request) error {
slog.Debug("Following redirect for prov file", "url", req.URL.String())
return nil
},
}))
}
body, err := g.Get(u.String() + ".prov")
if err != nil {
if c.Verify == VerifyAlways {

@ -19,7 +19,9 @@ package getter
import (
"bytes"
"fmt"
"log/slog"
"net/http"
"os"
"slices"
"time"
@ -47,6 +49,7 @@ type options struct {
registryClient *registry.Client
timeout time.Duration
transport *http.Transport
client *http.Client
}
// Option allows specifying various settings configurable by the user for overriding the defaults
@ -191,6 +194,18 @@ const (
var defaultOptions = []Option{WithTimeout(time.Second * DefaultHTTPTimeout)}
func init() {
level := slog.LevelInfo
if os.Getenv("HELM_DEBUG") == "true" {
level = slog.LevelDebug
}
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
Level: level,
}))
slog.SetDefault(logger)
}
func Getters(extraOpts ...Option) Providers {
return Providers{
Provider{

@ -20,8 +20,10 @@ import (
"crypto/tls"
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"os"
"sync"
"helm.sh/helm/v4/internal/tlsutil"
@ -46,6 +48,8 @@ func (g *HTTPGetter) Get(href string, options ...Option) (*bytes.Buffer, error)
func (g *HTTPGetter) get(href string) (*bytes.Buffer, error) {
// Set a helm specific user agent so that a repo server and metrics can
// separate helm calls from other tools interacting with repos.
debug := os.Getenv("HELM_DEBUG") == "true"
req, err := http.NewRequest(http.MethodGet, href, nil)
if err != nil {
return nil, err
@ -80,17 +84,29 @@ func (g *HTTPGetter) get(href string) (*bytes.Buffer, error) {
}
}
client, err := g.httpClient()
if err != nil {
return nil, err
client := g.opts.client
if client == nil {
var err error
client, err = g.httpClient()
if err != nil {
return nil, err
}
}
if debug {
slog.Debug("HTTP GET request", "url", href)
}
resp, err := client.Do(req)
if err != nil {
if debug {
slog.Debug("HTTP GET failed", "error", err)
}
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
slog.Debug("HTTP GET non-OK response", "url", href, "status", resp.Status)
return nil, fmt.Errorf("failed to fetch %s : %s", href, resp.Status)
}
@ -158,3 +174,10 @@ func (g *HTTPGetter) httpClient() (*http.Client, error) {
return client, nil
}
// WithClient sets the HTTP client for the getter
func WithClient(client *http.Client) Option {
return func(opts *options) {
opts.client = client
}
}

Loading…
Cancel
Save