Skip to content

Commit 38ce692

Browse files
committed
test
Signed-off-by: ChengyuZhu6 <[email protected]>
1 parent b5584fe commit 38ce692

File tree

4 files changed

+104
-14
lines changed

4 files changed

+104
-14
lines changed

cmd/nerdctl/container/container_run_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ func TestRunFromOCIArchive(t *testing.T) {
786786
tarPath := fmt.Sprintf("%s/%s.tar", buildCtx, imageName)
787787

788788
base.Cmd("build", "--tag", tag, fmt.Sprintf("--output=type=oci,dest=%s", tarPath), buildCtx).AssertOK()
789-
base.Cmd("run", "--rm", fmt.Sprintf("oci-archive://%s", tarPath)).AssertOutContainsAll(fmt.Sprintf("Loaded image: %s", tag), sentinel)
789+
base.Cmd("run", "--rm", fmt.Sprintf("oci-archive://%s", tarPath)).AssertOutContainsAll(tag, sentinel)
790790
}
791791

792792
func TestRunDomainname(t *testing.T) {

pkg/errutil/errors_check.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,18 @@ func IsErrConnectionRefused(err error) bool {
2424
const errMessage = "connect: connection refused"
2525
return strings.Contains(err.Error(), errMessage)
2626
}
27+
28+
// IsErrHTTPResponseToHTTPSClient returns whether err is
29+
// "http: server gave HTTP response to HTTPS client"
30+
func IsErrHTTPResponseToHTTPSClient(err error) bool {
31+
const errMessage = "server gave HTTP response to HTTPS client"
32+
return strings.Contains(err.Error(), errMessage)
33+
}
34+
35+
// IsErrTLSHandshakeFailure returns whether err is a TLS handshake or certificate verification error
36+
func IsErrTLSHandshakeFailure(err error) bool {
37+
errStr := err.Error()
38+
return strings.Contains(errStr, "tls:") ||
39+
strings.Contains(errStr, "x509:") ||
40+
strings.Contains(errStr, "certificate")
41+
}

pkg/imgutil/dockerconfigresolver/dockerconfigresolver.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ import (
2020
"context"
2121
"crypto/tls"
2222
"errors"
23+
"fmt"
24+
"os"
25+
"path/filepath"
26+
27+
"github.com/pelletier/go-toml/v2"
2328

2429
"github.com/containerd/containerd/v2/core/remotes"
2530
"github.com/containerd/containerd/v2/core/remotes/docker"
@@ -218,3 +223,46 @@ func (ch *credentialHelper) GetCredentials(ctx context.Context, ref, host string
218223
Secret: secret,
219224
}, nil
220225
}
226+
227+
type hostFileConfig struct {
228+
SkipVerify *bool `toml:"skip_verify,omitempty"`
229+
}
230+
231+
// CreateTmpHostsConfig creates a temporary hosts directory with hosts.toml configured for skip_verify
232+
// Returns the temporary directory path or empty string if creation failed
233+
func CreateTmpHostsConfig(hostname string, skipVerify bool) (string, error) {
234+
if !skipVerify {
235+
return "", nil
236+
}
237+
238+
tempDir, err := os.MkdirTemp("", "nerdctl-hosts-*")
239+
if err != nil {
240+
return "", fmt.Errorf("failed to create temp directory: %w", err)
241+
}
242+
243+
hostDir := filepath.Join(tempDir, hostname)
244+
if err := os.MkdirAll(hostDir, 0755); err != nil {
245+
os.RemoveAll(tempDir)
246+
return "", fmt.Errorf("failed to create host directory: %w", err)
247+
}
248+
249+
config := hostFileConfig{}
250+
if skipVerify {
251+
skip := true
252+
config.SkipVerify = &skip
253+
}
254+
255+
data, err := toml.Marshal(config)
256+
if err != nil {
257+
os.RemoveAll(tempDir)
258+
return "", fmt.Errorf("failed to marshal hosts config: %w", err)
259+
}
260+
261+
hostsTomlPath := filepath.Join(hostDir, "hosts.toml")
262+
if err := os.WriteFile(hostsTomlPath, data, 0644); err != nil {
263+
os.RemoveAll(tempDir)
264+
return "", fmt.Errorf("failed to write hosts.toml: %w", err)
265+
}
266+
267+
return tempDir, nil
268+
}

pkg/imgutil/transfer.go

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"io"
88
"net/http"
9+
"os"
910

1011
containerd "github.com/containerd/containerd/v2/client"
1112
"github.com/containerd/containerd/v2/core/remotes/docker"
@@ -45,27 +46,49 @@ func prepareImageStore(ctx context.Context, parsedReference *referenceutil.Image
4546
return transferimage.NewStore(parsedReference.String(), storeOpts...), nil
4647
}
4748

48-
func createOCIRegistry(ctx context.Context, parsedReference *referenceutil.ImageReference, gOptions types.GlobalCommandOptions, plainHTTP bool) (*registry.OCIRegistry, error) {
49+
func createOCIRegistry(ctx context.Context, parsedReference *referenceutil.ImageReference, gOptions types.GlobalCommandOptions, plainHTTP bool) (*registry.OCIRegistry, func(), error) {
4950
ch, err := dockerconfigresolver.NewCredentialHelper(parsedReference.Domain)
5051
if err != nil {
51-
return nil, err
52+
return nil, nil, err
5253
}
5354

5455
opts := []registry.Opt{
5556
registry.WithCredentials(ch),
5657
}
5758

58-
if len(gOptions.HostsDir) > 0 {
59+
var tmpHostsDir string
60+
cleanup := func() {
61+
if tmpHostsDir != "" {
62+
os.RemoveAll(tmpHostsDir)
63+
}
64+
}
65+
66+
// If insecure-registry is set, create a temporary hosts.toml with skip_verify
67+
if gOptions.InsecureRegistry {
68+
tmpHostsDir, err = dockerconfigresolver.CreateTmpHostsConfig(parsedReference.Domain, true)
69+
if err != nil {
70+
log.G(ctx).WithError(err).Warnf("failed to create temporary hosts.toml for %q, continuing without it", parsedReference.Domain)
71+
} else if tmpHostsDir != "" {
72+
opts = append(opts, registry.WithHostDir(tmpHostsDir))
73+
}
74+
} else if len(gOptions.HostsDir) > 0 {
5975
opts = append(opts, registry.WithHostDir(gOptions.HostsDir[0]))
6076
}
6177

6278
if isLocalHost, err := docker.MatchLocalhost(parsedReference.Domain); err != nil {
63-
return nil, err
79+
cleanup()
80+
return nil, nil, err
6481
} else if isLocalHost || plainHTTP {
6582
opts = append(opts, registry.WithDefaultScheme("http"))
6683
}
6784

68-
return registry.NewOCIRegistry(ctx, parsedReference.String(), opts...)
85+
reg, err := registry.NewOCIRegistry(ctx, parsedReference.String(), opts...)
86+
if err != nil {
87+
cleanup()
88+
return nil, nil, err
89+
}
90+
91+
return reg, cleanup, nil
6992
}
7093

7194
func PullImageWithTransfer(ctx context.Context, client *containerd.Client, parsedReference *referenceutil.ImageReference, rawRef string, options types.ImagePullOptions) (*EnsuredImage, error) {
@@ -79,20 +102,22 @@ func PullImageWithTransfer(ctx context.Context, client *containerd.Client, parse
79102
progressWriter = options.Stdout
80103
}
81104

82-
fetcher, err := createOCIRegistry(ctx, parsedReference, options.GOptions, false)
105+
fetcher, cleanup, err := createOCIRegistry(ctx, parsedReference, options.GOptions, false)
83106
if err != nil {
84107
return nil, err
85108
}
109+
defer cleanup()
86110

87111
transferErr := doTransfer(ctx, client, fetcher, store, options.Quiet, progressWriter)
88112

89-
if transferErr != nil && (errors.Is(transferErr, http.ErrSchemeMismatch) || errutil.IsErrConnectionRefused(transferErr)) {
113+
if transferErr != nil && (errors.Is(transferErr, http.ErrSchemeMismatch) || errutil.IsErrConnectionRefused(transferErr) || errutil.IsErrHTTPResponseToHTTPSClient(transferErr) || errutil.IsErrTLSHandshakeFailure(transferErr)) {
90114
if options.GOptions.InsecureRegistry {
91-
log.G(ctx).WithError(err).Warnf("server %q does not seem to support HTTPS, falling back to plain HTTP", parsedReference.Domain)
92-
fetcher, err = createOCIRegistry(ctx, parsedReference, options.GOptions, true)
115+
log.G(ctx).WithError(transferErr).Warnf("server %q does not seem to support HTTPS, falling back to plain HTTP", parsedReference.Domain)
116+
fetcher, cleanup2, err := createOCIRegistry(ctx, parsedReference, options.GOptions, true)
93117
if err != nil {
94118
return nil, err
95119
}
120+
defer cleanup2()
96121
transferErr = doTransfer(ctx, client, fetcher, store, options.Quiet, progressWriter)
97122
}
98123
}
@@ -151,20 +176,22 @@ func PushImageWithTransfer(ctx context.Context, client *containerd.Client, parse
151176
progressWriter = options.Stdout
152177
}
153178

154-
pusher, err := createOCIRegistry(ctx, parsedReference, options.GOptions, false)
179+
pusher, cleanup, err := createOCIRegistry(ctx, parsedReference, options.GOptions, false)
155180
if err != nil {
156181
return err
157182
}
183+
defer cleanup()
158184

159185
transferErr := doTransfer(ctx, client, source, pusher, options.Quiet, progressWriter)
160186

161-
if transferErr != nil && (errors.Is(transferErr, http.ErrSchemeMismatch) || errutil.IsErrConnectionRefused(transferErr)) {
187+
if transferErr != nil && (errors.Is(transferErr, http.ErrSchemeMismatch) || errutil.IsErrConnectionRefused(transferErr) || errutil.IsErrHTTPResponseToHTTPSClient(transferErr) || errutil.IsErrTLSHandshakeFailure(transferErr)) {
162188
if options.GOptions.InsecureRegistry {
163-
log.G(ctx).WithError(err).Warnf("server %q does not seem to support HTTPS, falling back to plain HTTP", parsedReference.Domain)
164-
pusher, err = createOCIRegistry(ctx, parsedReference, options.GOptions, true)
189+
log.G(ctx).WithError(transferErr).Warnf("server %q does not seem to support HTTPS, falling back to plain HTTP", parsedReference.Domain)
190+
pusher, cleanup2, err := createOCIRegistry(ctx, parsedReference, options.GOptions, true)
165191
if err != nil {
166192
return err
167193
}
194+
defer cleanup2()
168195
transferErr = doTransfer(ctx, client, source, pusher, options.Quiet, progressWriter)
169196
}
170197
}

0 commit comments

Comments
 (0)