client/image_remove&search: Wrap options and result

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
Paweł Gronowski
2025-10-20 19:27:20 +02:00
committed by Austin Vazquez
parent b3974f07f5
commit 347693a580
14 changed files with 64 additions and 36 deletions

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/api/types/plugin"
"github.com/moby/moby/api/types/registry"
@@ -114,8 +113,8 @@ type ImageAPIClient interface {
ImageList(ctx context.Context, options ImageListOptions) (ImageListResult, error)
ImagePull(ctx context.Context, ref string, options ImagePullOptions) (ImagePullResponse, error)
ImagePush(ctx context.Context, ref string, options ImagePushOptions) (ImagePushResponse, error)
ImageRemove(ctx context.Context, image string, options ImageRemoveOptions) ([]image.DeleteResponse, error)
ImageSearch(ctx context.Context, term string, options ImageSearchOptions) ([]registry.SearchResult, error)
ImageRemove(ctx context.Context, image string, options ImageRemoveOptions) (ImageRemoveResult, error)
ImageSearch(ctx context.Context, term string, options ImageSearchOptions) (ImageSearchResult, error)
ImageTag(ctx context.Context, image, ref string) error
ImagesPrune(ctx context.Context, opts ImagePruneOptions) (ImagePruneResult, error)

View File

@@ -9,7 +9,7 @@ import (
)
// ImageRemove removes an image from the docker host.
func (cli *Client) ImageRemove(ctx context.Context, imageID string, options ImageRemoveOptions) ([]image.DeleteResponse, error) {
func (cli *Client) ImageRemove(ctx context.Context, imageID string, options ImageRemoveOptions) (ImageRemoveResult, error) {
query := url.Values{}
if options.Force {
@@ -22,7 +22,7 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options Imag
if len(options.Platforms) > 0 {
p, err := encodePlatforms(options.Platforms...)
if err != nil {
return nil, err
return ImageRemoveResult{}, err
}
query["platforms"] = p
}
@@ -30,10 +30,10 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options Imag
resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
return ImageRemoveResult{}, err
}
var dels []image.DeleteResponse
err = json.NewDecoder(resp.Body).Decode(&dels)
return dels, err
return ImageRemoveResult{Deleted: dels}, err
}

View File

@@ -1,6 +1,9 @@
package client
import ocispec "github.com/opencontainers/image-spec/specs-go/v1"
import (
"github.com/moby/moby/api/types/image"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// ImageRemoveOptions holds parameters to remove images.
type ImageRemoveOptions struct {
@@ -8,3 +11,8 @@ type ImageRemoveOptions struct {
Force bool
PruneChildren bool
}
// ImageRemoveResult holds the delete responses returned by the daemon.
type ImageRemoveResult struct {
Deleted []image.DeleteResponse
}

View File

@@ -108,6 +108,6 @@ func TestImageRemove(t *testing.T) {
imageDeletes, err := client.ImageRemove(context.Background(), "image_id", opts)
assert.NilError(t, err)
assert.Check(t, is.Len(imageDeletes, 2))
assert.Check(t, is.Len(imageDeletes.Deleted, 2))
}
}

View File

@@ -13,7 +13,7 @@ import (
// ImageSearch makes the docker host search by a term in a remote registry.
// The list of results is not sorted in any fashion.
func (cli *Client) ImageSearch(ctx context.Context, term string, options ImageSearchOptions) ([]registry.SearchResult, error) {
func (cli *Client) ImageSearch(ctx context.Context, term string, options ImageSearchOptions) (ImageSearchResult, error) {
var results []registry.SearchResult
query := url.Values{}
query.Set("term", term)
@@ -28,16 +28,16 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options ImageSe
if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx)
if privilegeErr != nil {
return results, privilegeErr
return ImageSearchResult{}, privilegeErr
}
resp, err = cli.tryImageSearch(ctx, query, newAuthHeader)
}
if err != nil {
return results, err
return ImageSearchResult{}, err
}
err = json.NewDecoder(resp.Body).Decode(&results)
return results, err
return ImageSearchResult{Items: results}, err
}
func (cli *Client) tryImageSearch(ctx context.Context, query url.Values, registryAuth string) (*http.Response, error) {

View File

@@ -2,8 +2,15 @@ package client
import (
"context"
"github.com/moby/moby/api/types/registry"
)
// ImageSearchResult wraps results returned by ImageSearch.
type ImageSearchResult struct {
Items []registry.SearchResult
}
// ImageSearchOptions holds parameters to search images with.
type ImageSearchOptions struct {
RegistryAuth string

View File

@@ -97,7 +97,7 @@ func TestImageSearchWithPrivilegedFuncNoError(t *testing.T) {
PrivilegeFunc: privilegeFunc,
})
assert.NilError(t, err)
assert.Check(t, is.Len(results, 1))
assert.Check(t, is.Len(results.Items, 1))
}
func TestImageSearchWithoutErrors(t *testing.T) {
@@ -135,5 +135,5 @@ func TestImageSearchWithoutErrors(t *testing.T) {
Filters: make(Filters).Add("is-automated", "true").Add("stars", "3"),
})
assert.NilError(t, err)
assert.Check(t, is.Len(results, 1))
assert.Check(t, is.Len(results.Items, 1))
}

View File

@@ -800,9 +800,9 @@ func TestBuildHistoryDoesNotPreventRemoval(t *testing.T) {
err := buildImage("history-a")
assert.NilError(t, err)
resp, err := apiClient.ImageRemove(ctx, "history-a", client.ImageRemoveOptions{})
res, err := apiClient.ImageRemove(ctx, "history-a", client.ImageRemoveOptions{})
assert.NilError(t, err)
assert.Check(t, slices.ContainsFunc(resp, func(r image.DeleteResponse) bool {
assert.Check(t, slices.ContainsFunc(res.Deleted, func(r image.DeleteResponse) bool {
return r.Deleted != ""
}))
}

View File

@@ -142,25 +142,25 @@ func TestRemoveWithPlatform(t *testing.T) {
{platform: &platformHost, deleted: descs[0]},
{platform: &someOtherPlatform, deleted: descs[3]},
} {
resp, err := apiClient.ImageRemove(ctx, imgName, client.ImageRemoveOptions{
res, err := apiClient.ImageRemove(ctx, imgName, client.ImageRemoveOptions{
Platforms: []ocispec.Platform{*tc.platform},
Force: true,
})
assert.NilError(t, err)
assert.Check(t, is.Len(resp, 1))
for _, r := range resp {
assert.Check(t, is.Len(res.Deleted, 1))
for _, r := range res.Deleted {
assert.Check(t, is.Equal(r.Untagged, ""), "No image should be untagged")
}
checkPlatformDeleted(t, imageIdx, resp, tc.deleted)
checkPlatformDeleted(t, imageIdx, res.Deleted, tc.deleted)
}
// Delete the rest
resp, err := apiClient.ImageRemove(ctx, imgName, client.ImageRemoveOptions{})
assert.NilError(t, err)
assert.Check(t, is.Len(resp, 2))
assert.Check(t, is.Equal(resp[0].Untagged, imgName))
assert.Check(t, is.Equal(resp[1].Deleted, imageIdx.Manifests[0].Digest.String()))
assert.Check(t, is.Len(resp.Deleted, 2))
assert.Check(t, is.Equal(resp.Deleted[0].Untagged, imgName))
assert.Check(t, is.Equal(resp.Deleted[1].Deleted, imageIdx.Manifests[0].Digest.String()))
// TODO(vvoland): Should it also include platform-specific manifests? https://github.com/moby/moby/pull/49982
}

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/events"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/api/types/plugin"
"github.com/moby/moby/api/types/registry"
@@ -114,8 +113,8 @@ type ImageAPIClient interface {
ImageList(ctx context.Context, options ImageListOptions) (ImageListResult, error)
ImagePull(ctx context.Context, ref string, options ImagePullOptions) (ImagePullResponse, error)
ImagePush(ctx context.Context, ref string, options ImagePushOptions) (ImagePushResponse, error)
ImageRemove(ctx context.Context, image string, options ImageRemoveOptions) ([]image.DeleteResponse, error)
ImageSearch(ctx context.Context, term string, options ImageSearchOptions) ([]registry.SearchResult, error)
ImageRemove(ctx context.Context, image string, options ImageRemoveOptions) (ImageRemoveResult, error)
ImageSearch(ctx context.Context, term string, options ImageSearchOptions) (ImageSearchResult, error)
ImageTag(ctx context.Context, image, ref string) error
ImagesPrune(ctx context.Context, opts ImagePruneOptions) (ImagePruneResult, error)

View File

@@ -9,7 +9,7 @@ import (
)
// ImageRemove removes an image from the docker host.
func (cli *Client) ImageRemove(ctx context.Context, imageID string, options ImageRemoveOptions) ([]image.DeleteResponse, error) {
func (cli *Client) ImageRemove(ctx context.Context, imageID string, options ImageRemoveOptions) (ImageRemoveResult, error) {
query := url.Values{}
if options.Force {
@@ -22,7 +22,7 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options Imag
if len(options.Platforms) > 0 {
p, err := encodePlatforms(options.Platforms...)
if err != nil {
return nil, err
return ImageRemoveResult{}, err
}
query["platforms"] = p
}
@@ -30,10 +30,10 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options Imag
resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
return ImageRemoveResult{}, err
}
var dels []image.DeleteResponse
err = json.NewDecoder(resp.Body).Decode(&dels)
return dels, err
return ImageRemoveResult{Deleted: dels}, err
}

View File

@@ -1,6 +1,9 @@
package client
import ocispec "github.com/opencontainers/image-spec/specs-go/v1"
import (
"github.com/moby/moby/api/types/image"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// ImageRemoveOptions holds parameters to remove images.
type ImageRemoveOptions struct {
@@ -8,3 +11,8 @@ type ImageRemoveOptions struct {
Force bool
PruneChildren bool
}
// ImageRemoveResult holds the delete responses returned by the daemon.
type ImageRemoveResult struct {
Deleted []image.DeleteResponse
}

View File

@@ -13,7 +13,7 @@ import (
// ImageSearch makes the docker host search by a term in a remote registry.
// The list of results is not sorted in any fashion.
func (cli *Client) ImageSearch(ctx context.Context, term string, options ImageSearchOptions) ([]registry.SearchResult, error) {
func (cli *Client) ImageSearch(ctx context.Context, term string, options ImageSearchOptions) (ImageSearchResult, error) {
var results []registry.SearchResult
query := url.Values{}
query.Set("term", term)
@@ -28,16 +28,16 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options ImageSe
if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx)
if privilegeErr != nil {
return results, privilegeErr
return ImageSearchResult{}, privilegeErr
}
resp, err = cli.tryImageSearch(ctx, query, newAuthHeader)
}
if err != nil {
return results, err
return ImageSearchResult{}, err
}
err = json.NewDecoder(resp.Body).Decode(&results)
return results, err
return ImageSearchResult{Items: results}, err
}
func (cli *Client) tryImageSearch(ctx context.Context, query url.Values, registryAuth string) (*http.Response, error) {

View File

@@ -2,8 +2,15 @@ package client
import (
"context"
"github.com/moby/moby/api/types/registry"
)
// ImageSearchResult wraps results returned by ImageSearch.
type ImageSearchResult struct {
Items []registry.SearchResult
}
// ImageSearchOptions holds parameters to search images with.
type ImageSearchOptions struct {
RegistryAuth string