Browse code

client: Remove ImageCreate in favor of ImagePull/ImageImport

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>

Paweł Gronowski authored on 2025/10/31 22:48:54
Showing 9 changed files
... ...
@@ -96,7 +96,6 @@ type ImageAPIClient interface {
96 96
 	ImageBuild(ctx context.Context, context io.Reader, options ImageBuildOptions) (ImageBuildResult, error)
97 97
 	BuildCachePrune(ctx context.Context, opts BuildCachePruneOptions) (BuildCachePruneResult, error)
98 98
 	BuildCancel(ctx context.Context, id string, opts BuildCancelOptions) (BuildCancelResult, error)
99
-	ImageCreate(ctx context.Context, parentReference string, options ImageCreateOptions) (ImageCreateResult, error)
100 99
 	ImageImport(ctx context.Context, source ImageImportSource, ref string, options ImageImportOptions) (ImageImportResult, error)
101 100
 
102 101
 	ImageList(ctx context.Context, options ImageListOptions) (ImageListResult, error)
103 102
deleted file mode 100644
... ...
@@ -1,50 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"context"
5
-	"net/http"
6
-	"net/url"
7
-
8
-	cerrdefs "github.com/containerd/errdefs"
9
-	"github.com/distribution/reference"
10
-	"github.com/moby/moby/api/types/registry"
11
-)
12
-
13
-// ImageCreate creates a new image based on the parent options.
14
-// It returns the JSON content in the response body.
15
-func (cli *Client) ImageCreate(ctx context.Context, parentReference string, options ImageCreateOptions) (ImageCreateResult, error) {
16
-	ref, err := reference.ParseNormalizedNamed(parentReference)
17
-	if err != nil {
18
-		return ImageCreateResult{}, err
19
-	}
20
-
21
-	query := url.Values{}
22
-	query.Set("fromImage", ref.Name())
23
-	query.Set("tag", getAPITagFromNamedRef(ref))
24
-	if len(options.Platforms) > 0 {
25
-		if len(options.Platforms) > 1 {
26
-			// TODO(thaJeztah): update API spec and add equivalent check on the daemon. We need this still for older daemons, which would ignore it.
27
-			return ImageCreateResult{}, cerrdefs.ErrInvalidArgument.WithMessage("specifying multiple platforms is not yet supported")
28
-		}
29
-		query.Set("platform", formatPlatform(options.Platforms[0]))
30
-	}
31
-	resp, err := cli.tryImageCreate(ctx, query, staticAuth(options.RegistryAuth))
32
-	if err != nil {
33
-		return ImageCreateResult{}, err
34
-	}
35
-	return ImageCreateResult{Body: resp.Body}, nil
36
-}
37
-
38
-func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, resolveAuth registry.RequestAuthConfig) (*http.Response, error) {
39
-	hdr := http.Header{}
40
-	if resolveAuth != nil {
41
-		registryAuth, err := resolveAuth(ctx)
42
-		if err != nil {
43
-			return nil, err
44
-		}
45
-		if registryAuth != "" {
46
-			hdr.Set(registry.AuthHeader, registryAuth)
47
-		}
48
-	}
49
-	return cli.post(ctx, "/images/create", query, nil, hdr)
50
-}
51 1
deleted file mode 100644
... ...
@@ -1,21 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"io"
5
-
6
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
7
-)
8
-
9
-// ImageCreateOptions holds information to create images.
10
-type ImageCreateOptions struct {
11
-	RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry.
12
-	// Platforms specifies the platforms to platform of the image if it needs
13
-	// to be pulled from the registry. Multiple platforms can be provided
14
-	// if the daemon supports multi-platform pulls.
15
-	Platforms []ocispec.Platform
16
-}
17
-
18
-// ImageCreateResult holds the response body returned by the daemon for image create.
19
-type ImageCreateResult struct {
20
-	Body io.ReadCloser
21
-}
22 1
deleted file mode 100644
... ...
@@ -1,65 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"context"
5
-	"fmt"
6
-	"io"
7
-	"net/http"
8
-	"testing"
9
-
10
-	cerrdefs "github.com/containerd/errdefs"
11
-	"github.com/moby/moby/api/types/registry"
12
-	"gotest.tools/v3/assert"
13
-	is "gotest.tools/v3/assert/cmp"
14
-)
15
-
16
-func TestImageCreateError(t *testing.T) {
17
-	client, err := New(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
18
-	assert.NilError(t, err)
19
-	_, err = client.ImageCreate(context.Background(), "reference", ImageCreateOptions{})
20
-	assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
21
-}
22
-
23
-func TestImageCreate(t *testing.T) {
24
-	const (
25
-		expectedURL          = "/images/create"
26
-		expectedImage        = "docker.io/test/my_image"
27
-		expectedTag          = "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
28
-		specifiedReference   = "test/my_image:latest@" + expectedTag
29
-		expectedRegistryAuth = "eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsiYXV0aCI6ImRHOTBid289IiwiZW1haWwiOiJqb2huQGRvZS5jb20ifX0="
30
-	)
31
-
32
-	client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) {
33
-		if err := assertRequest(req, http.MethodPost, expectedURL); err != nil {
34
-			return nil, err
35
-		}
36
-		registryAuth := req.Header.Get(registry.AuthHeader)
37
-		if registryAuth != expectedRegistryAuth {
38
-			return nil, fmt.Errorf("%s header not properly set in the request. Expected '%s', got %s", registry.AuthHeader, expectedRegistryAuth, registryAuth)
39
-		}
40
-
41
-		query := req.URL.Query()
42
-		fromImage := query.Get("fromImage")
43
-		if fromImage != expectedImage {
44
-			return nil, fmt.Errorf("fromImage not set in URL query properly. Expected '%s', got %s", expectedImage, fromImage)
45
-		}
46
-
47
-		tag := query.Get("tag")
48
-		if tag != expectedTag {
49
-			return nil, fmt.Errorf("tag not set in URL query properly. Expected '%s', got %s", expectedTag, tag)
50
-		}
51
-
52
-		return mockResponse(http.StatusOK, nil, "body")(req)
53
-	}))
54
-	assert.NilError(t, err)
55
-
56
-	createResult, err := client.ImageCreate(context.Background(), specifiedReference, ImageCreateOptions{
57
-		RegistryAuth: expectedRegistryAuth,
58
-	})
59
-	assert.NilError(t, err)
60
-	response, err := io.ReadAll(createResult.Body)
61
-	assert.NilError(t, err)
62
-	err = createResult.Body.Close()
63
-	assert.NilError(t, err)
64
-	assert.Check(t, is.Equal(string(response), "body"))
65
-}
... ...
@@ -4,11 +4,13 @@ import (
4 4
 	"context"
5 5
 	"io"
6 6
 	"iter"
7
+	"net/http"
7 8
 	"net/url"
8 9
 
9 10
 	cerrdefs "github.com/containerd/errdefs"
10 11
 	"github.com/distribution/reference"
11 12
 	"github.com/moby/moby/api/types/jsonstream"
13
+	"github.com/moby/moby/api/types/registry"
12 14
 	"github.com/moby/moby/client/internal"
13 15
 )
14 16
 
... ...
@@ -75,3 +77,17 @@ func getAPITagFromNamedRef(ref reference.Named) string {
75 75
 	}
76 76
 	return ""
77 77
 }
78
+
79
+func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, resolveAuth registry.RequestAuthConfig) (*http.Response, error) {
80
+	hdr := http.Header{}
81
+	if resolveAuth != nil {
82
+		registryAuth, err := resolveAuth(ctx)
83
+		if err != nil {
84
+			return nil, err
85
+		}
86
+		if registryAuth != "" {
87
+			hdr.Set(registry.AuthHeader, registryAuth)
88
+		}
89
+	}
90
+	return cli.post(ctx, "/images/create", query, nil, hdr)
91
+}
... ...
@@ -96,7 +96,6 @@ type ImageAPIClient interface {
96 96
 	ImageBuild(ctx context.Context, context io.Reader, options ImageBuildOptions) (ImageBuildResult, error)
97 97
 	BuildCachePrune(ctx context.Context, opts BuildCachePruneOptions) (BuildCachePruneResult, error)
98 98
 	BuildCancel(ctx context.Context, id string, opts BuildCancelOptions) (BuildCancelResult, error)
99
-	ImageCreate(ctx context.Context, parentReference string, options ImageCreateOptions) (ImageCreateResult, error)
100 99
 	ImageImport(ctx context.Context, source ImageImportSource, ref string, options ImageImportOptions) (ImageImportResult, error)
101 100
 
102 101
 	ImageList(ctx context.Context, options ImageListOptions) (ImageListResult, error)
103 102
deleted file mode 100644
... ...
@@ -1,50 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"context"
5
-	"net/http"
6
-	"net/url"
7
-
8
-	cerrdefs "github.com/containerd/errdefs"
9
-	"github.com/distribution/reference"
10
-	"github.com/moby/moby/api/types/registry"
11
-)
12
-
13
-// ImageCreate creates a new image based on the parent options.
14
-// It returns the JSON content in the response body.
15
-func (cli *Client) ImageCreate(ctx context.Context, parentReference string, options ImageCreateOptions) (ImageCreateResult, error) {
16
-	ref, err := reference.ParseNormalizedNamed(parentReference)
17
-	if err != nil {
18
-		return ImageCreateResult{}, err
19
-	}
20
-
21
-	query := url.Values{}
22
-	query.Set("fromImage", ref.Name())
23
-	query.Set("tag", getAPITagFromNamedRef(ref))
24
-	if len(options.Platforms) > 0 {
25
-		if len(options.Platforms) > 1 {
26
-			// TODO(thaJeztah): update API spec and add equivalent check on the daemon. We need this still for older daemons, which would ignore it.
27
-			return ImageCreateResult{}, cerrdefs.ErrInvalidArgument.WithMessage("specifying multiple platforms is not yet supported")
28
-		}
29
-		query.Set("platform", formatPlatform(options.Platforms[0]))
30
-	}
31
-	resp, err := cli.tryImageCreate(ctx, query, staticAuth(options.RegistryAuth))
32
-	if err != nil {
33
-		return ImageCreateResult{}, err
34
-	}
35
-	return ImageCreateResult{Body: resp.Body}, nil
36
-}
37
-
38
-func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, resolveAuth registry.RequestAuthConfig) (*http.Response, error) {
39
-	hdr := http.Header{}
40
-	if resolveAuth != nil {
41
-		registryAuth, err := resolveAuth(ctx)
42
-		if err != nil {
43
-			return nil, err
44
-		}
45
-		if registryAuth != "" {
46
-			hdr.Set(registry.AuthHeader, registryAuth)
47
-		}
48
-	}
49
-	return cli.post(ctx, "/images/create", query, nil, hdr)
50
-}
51 1
deleted file mode 100644
... ...
@@ -1,21 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"io"
5
-
6
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
7
-)
8
-
9
-// ImageCreateOptions holds information to create images.
10
-type ImageCreateOptions struct {
11
-	RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry.
12
-	// Platforms specifies the platforms to platform of the image if it needs
13
-	// to be pulled from the registry. Multiple platforms can be provided
14
-	// if the daemon supports multi-platform pulls.
15
-	Platforms []ocispec.Platform
16
-}
17
-
18
-// ImageCreateResult holds the response body returned by the daemon for image create.
19
-type ImageCreateResult struct {
20
-	Body io.ReadCloser
21
-}
... ...
@@ -4,11 +4,13 @@ import (
4 4
 	"context"
5 5
 	"io"
6 6
 	"iter"
7
+	"net/http"
7 8
 	"net/url"
8 9
 
9 10
 	cerrdefs "github.com/containerd/errdefs"
10 11
 	"github.com/distribution/reference"
11 12
 	"github.com/moby/moby/api/types/jsonstream"
13
+	"github.com/moby/moby/api/types/registry"
12 14
 	"github.com/moby/moby/client/internal"
13 15
 )
14 16
 
... ...
@@ -75,3 +77,17 @@ func getAPITagFromNamedRef(ref reference.Named) string {
75 75
 	}
76 76
 	return ""
77 77
 }
78
+
79
+func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, resolveAuth registry.RequestAuthConfig) (*http.Response, error) {
80
+	hdr := http.Header{}
81
+	if resolveAuth != nil {
82
+		registryAuth, err := resolveAuth(ctx)
83
+		if err != nil {
84
+			return nil, err
85
+		}
86
+		if registryAuth != "" {
87
+			hdr.Set(registry.AuthHeader, registryAuth)
88
+		}
89
+	}
90
+	return cli.post(ctx, "/images/create", query, nil, hdr)
91
+}