Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
| ... | ... |
@@ -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 |
+} |