mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
move endpoint API version constraints to API server
This introduces a `WithMinimumAPIVersion` RouteWrapper to configure the
minimum API version required for a route. It produces a 400 (Invalid Request)
error when accessing the endpoint on API versions lower than the given version.
Note that technically, it should produce a 404 ("not found") error,
as the endpoint should be considered "non-existing" on such API versions,
but 404 status-codes are used in business logic for various endpoints.
This patch allows removal of corresponding API-version checks from the client,
and other implementation of clients for the API. While the produced error message
is slightly more "technical", these situations should be rare and only happen
when the API version of the client is explicitly overridden, or a client was
implemented with a fixed API version (potentially missing version checks).
Before this patch, these errors were produced by the client:
DOCKER_API_VERSION=v1.24 docker container prune -f
docker container prune requires API version 1.25, but the Docker daemon API version is 1.24
With this patch applied, the error is returned by the daemon:
DOCKER_API_VERSION=v1.24 docker container prune -f
Error response from daemon: POST /containers/prune requires minimum API version 1.25
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
@@ -23,10 +23,6 @@ type BuildCachePruneOptions struct {
|
||||
|
||||
// BuildCachePrune requests the daemon to delete unused cache data.
|
||||
func (cli *Client) BuildCachePrune(ctx context.Context, opts BuildCachePruneOptions) (*build.CachePruneReport, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.31", "build prune"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
if opts.All {
|
||||
query.Set("all", "1")
|
||||
|
||||
@@ -9,16 +9,13 @@ import (
|
||||
|
||||
// ConfigCreate creates a new config.
|
||||
func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
|
||||
var response swarm.ConfigCreateResponse
|
||||
if err := cli.NewVersionError(ctx, "1.30", "config create"); err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := cli.post(ctx, "/configs/create", nil, config, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return response, err
|
||||
return swarm.ConfigCreateResponse{}, err
|
||||
}
|
||||
|
||||
var response swarm.ConfigCreateResponse
|
||||
err = json.NewDecoder(resp.Body).Decode(&response)
|
||||
return response, err
|
||||
}
|
||||
|
||||
@@ -16,17 +16,6 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestConfigCreateUnsupported(t *testing.T) {
|
||||
client, err := NewClientWithOpts(
|
||||
WithVersion("1.29"),
|
||||
WithHTTPClient(&http.Client{}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ConfigCreate(context.Background(), swarm.ConfigSpec{})
|
||||
assert.Check(t, is.Error(err, `"config create" requires API version 1.30, but the Docker daemon API version is 1.29`))
|
||||
}
|
||||
|
||||
func TestConfigCreateError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(
|
||||
WithVersion("1.30"),
|
||||
|
||||
@@ -15,9 +15,6 @@ func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.C
|
||||
if err != nil {
|
||||
return swarm.Config{}, nil, err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.30", "config inspect"); err != nil {
|
||||
return swarm.Config{}, nil, err
|
||||
}
|
||||
resp, err := cli.get(ctx, "/configs/"+id, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
|
||||
@@ -43,17 +43,6 @@ func TestConfigInspectWithEmptyID(t *testing.T) {
|
||||
assert.Check(t, is.ErrorContains(err, "value is empty"))
|
||||
}
|
||||
|
||||
func TestConfigInspectUnsupported(t *testing.T) {
|
||||
client, err := NewClientWithOpts(
|
||||
WithVersion("1.29"),
|
||||
WithHTTPClient(&http.Client{}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, _, err = client.ConfigInspectWithRaw(context.Background(), "nothing")
|
||||
assert.Check(t, is.Error(err, `"config inspect" requires API version 1.30, but the Docker daemon API version is 1.29`))
|
||||
}
|
||||
|
||||
func TestConfigInspectError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(
|
||||
WithVersion("1.30"),
|
||||
|
||||
@@ -11,9 +11,6 @@ import (
|
||||
|
||||
// ConfigList returns the list of configs.
|
||||
func (cli *Client) ConfigList(ctx context.Context, options ConfigListOptions) ([]swarm.Config, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.30", "config list"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query := url.Values{}
|
||||
|
||||
if options.Filters.Len() > 0 {
|
||||
|
||||
@@ -17,17 +17,6 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestConfigListUnsupported(t *testing.T) {
|
||||
client, err := NewClientWithOpts(
|
||||
WithVersion("1.29"),
|
||||
WithHTTPClient(&http.Client{}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
_, err = client.ConfigList(context.Background(), ConfigListOptions{})
|
||||
assert.Check(t, is.Error(err, `"config list" requires API version 1.30, but the Docker daemon API version is 1.29`))
|
||||
}
|
||||
|
||||
func TestConfigListError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(
|
||||
WithVersion("1.30"),
|
||||
|
||||
@@ -8,9 +8,6 @@ func (cli *Client) ConfigRemove(ctx context.Context, id string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.30", "config remove"); err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := cli.delete(ctx, "/configs/"+id, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
|
||||
@@ -14,17 +14,6 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestConfigRemoveUnsupported(t *testing.T) {
|
||||
client, err := NewClientWithOpts(
|
||||
WithVersion("1.29"),
|
||||
WithHTTPClient(&http.Client{}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.ConfigRemove(context.Background(), "config_id")
|
||||
assert.Check(t, is.Error(err, `"config remove" requires API version 1.30, but the Docker daemon API version is 1.29`))
|
||||
}
|
||||
|
||||
func TestConfigRemoveError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(
|
||||
WithVersion("1.30"),
|
||||
|
||||
@@ -13,9 +13,6 @@ func (cli *Client) ConfigUpdate(ctx context.Context, id string, version swarm.Ve
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.30", "config update"); err != nil {
|
||||
return err
|
||||
}
|
||||
query := url.Values{}
|
||||
query.Set("version", version.String())
|
||||
resp, err := cli.post(ctx, "/configs/"+id+"/update", query, config, nil)
|
||||
|
||||
@@ -15,17 +15,6 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestConfigUpdateUnsupported(t *testing.T) {
|
||||
client, err := NewClientWithOpts(
|
||||
WithVersion("1.29"),
|
||||
WithHTTPClient(&http.Client{}),
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
|
||||
err = client.ConfigUpdate(context.Background(), "config_id", swarm.Version{}, swarm.ConfigSpec{})
|
||||
assert.Check(t, is.Error(err, `"config update" requires API version 1.30, but the Docker daemon API version is 1.29`))
|
||||
}
|
||||
|
||||
func TestConfigUpdateError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(
|
||||
WithVersion("1.30"),
|
||||
|
||||
@@ -11,10 +11,6 @@ import (
|
||||
|
||||
// ContainersPrune requests the daemon to delete unused data
|
||||
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.25", "container prune"); err != nil {
|
||||
return container.PruneReport{}, err
|
||||
}
|
||||
|
||||
query, err := getFiltersQuery(pruneFilters)
|
||||
if err != nil {
|
||||
return container.PruneReport{}, err
|
||||
|
||||
@@ -15,10 +15,6 @@ func (cli *Client) DistributionInspect(ctx context.Context, imageRef, encodedReg
|
||||
return registry.DistributionInspect{}, objectNotFoundError{object: "distribution", id: imageRef}
|
||||
}
|
||||
|
||||
if err := cli.NewVersionError(ctx, "1.30", "distribution inspect"); err != nil {
|
||||
return registry.DistributionInspect{}, err
|
||||
}
|
||||
|
||||
var headers http.Header
|
||||
if encodedRegistryAuth != "" {
|
||||
headers = http.Header{
|
||||
|
||||
@@ -11,13 +11,6 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestDistributionInspectUnsupported(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithVersion("1.29"), WithHTTPClient(&http.Client{}))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.DistributionInspect(context.Background(), "foobar:1.0", "")
|
||||
assert.Check(t, is.Error(err, `"distribution inspect" requires API version 1.30, but the Docker daemon API version is 1.29`))
|
||||
}
|
||||
|
||||
func TestDistributionInspectWithEmptyID(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithMockClient(func(req *http.Request) (*http.Response, error) {
|
||||
return nil, errors.New("should not make request")
|
||||
|
||||
@@ -11,10 +11,6 @@ import (
|
||||
|
||||
// ImagesPrune requests the daemon to delete unused data
|
||||
func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (image.PruneReport, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.25", "image prune"); err != nil {
|
||||
return image.PruneReport{}, err
|
||||
}
|
||||
|
||||
query, err := getFiltersQuery(pruneFilters)
|
||||
if err != nil {
|
||||
return image.PruneReport{}, err
|
||||
|
||||
@@ -11,10 +11,6 @@ import (
|
||||
|
||||
// NetworksPrune requests the daemon to delete unused networks
|
||||
func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (network.PruneReport, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.25", "network prune"); err != nil {
|
||||
return network.PruneReport{}, err
|
||||
}
|
||||
|
||||
query, err := getFiltersQuery(pruneFilters)
|
||||
if err != nil {
|
||||
return network.PruneReport{}, err
|
||||
|
||||
@@ -19,9 +19,6 @@ func (cli *Client) PluginUpgrade(ctx context.Context, name string, options Plugi
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := cli.NewVersionError(ctx, "1.26", "plugin upgrade"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query := url.Values{}
|
||||
if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
|
||||
return nil, fmt.Errorf("invalid remote reference: %w", err)
|
||||
|
||||
@@ -9,9 +9,6 @@ import (
|
||||
|
||||
// SecretCreate creates a new secret.
|
||||
func (cli *Client) SecretCreate(ctx context.Context, secret swarm.SecretSpec) (swarm.SecretCreateResponse, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.25", "secret create"); err != nil {
|
||||
return swarm.SecretCreateResponse{}, err
|
||||
}
|
||||
resp, err := cli.post(ctx, "/secrets/create", nil, secret, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
|
||||
@@ -16,13 +16,6 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestSecretCreateUnsupported(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithVersion("1.24"), WithHTTPClient(&http.Client{}))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.SecretCreate(context.Background(), swarm.SecretSpec{})
|
||||
assert.Check(t, is.Error(err, `"secret create" requires API version 1.25, but the Docker daemon API version is 1.24`))
|
||||
}
|
||||
|
||||
func TestSecretCreateError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithVersion("1.25"), WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -15,9 +15,6 @@ func (cli *Client) SecretInspectWithRaw(ctx context.Context, id string) (swarm.S
|
||||
if err != nil {
|
||||
return swarm.Secret{}, nil, err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.25", "secret inspect"); err != nil {
|
||||
return swarm.Secret{}, nil, err
|
||||
}
|
||||
resp, err := cli.get(ctx, "/secrets/"+id, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
|
||||
@@ -17,13 +17,6 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestSecretInspectUnsupported(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithVersion("1.24"), WithHTTPClient(&http.Client{}))
|
||||
assert.NilError(t, err)
|
||||
_, _, err = client.SecretInspectWithRaw(context.Background(), "nothing")
|
||||
assert.Check(t, is.Error(err, `"secret inspect" requires API version 1.25, but the Docker daemon API version is 1.24`))
|
||||
}
|
||||
|
||||
func TestSecretInspectError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithVersion("1.25"), WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -11,9 +11,6 @@ import (
|
||||
|
||||
// SecretList returns the list of secrets.
|
||||
func (cli *Client) SecretList(ctx context.Context, options SecretListOptions) ([]swarm.Secret, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.25", "secret list"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query := url.Values{}
|
||||
|
||||
if options.Filters.Len() > 0 {
|
||||
|
||||
@@ -17,13 +17,6 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestSecretListUnsupported(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithVersion("1.24"), WithHTTPClient(&http.Client{}))
|
||||
assert.NilError(t, err)
|
||||
_, err = client.SecretList(context.Background(), SecretListOptions{})
|
||||
assert.Check(t, is.Error(err, `"secret list" requires API version 1.25, but the Docker daemon API version is 1.24`))
|
||||
}
|
||||
|
||||
func TestSecretListError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithVersion("1.25"), WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -8,9 +8,6 @@ func (cli *Client) SecretRemove(ctx context.Context, id string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.25", "secret remove"); err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := cli.delete(ctx, "/secrets/"+id, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
|
||||
@@ -14,13 +14,6 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestSecretRemoveUnsupported(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithVersion("1.24"), WithHTTPClient(&http.Client{}))
|
||||
assert.NilError(t, err)
|
||||
err = client.SecretRemove(context.Background(), "secret_id")
|
||||
assert.Check(t, is.Error(err, `"secret remove" requires API version 1.25, but the Docker daemon API version is 1.24`))
|
||||
}
|
||||
|
||||
func TestSecretRemoveError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithVersion("1.25"), WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -13,9 +13,6 @@ func (cli *Client) SecretUpdate(ctx context.Context, id string, version swarm.Ve
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.25", "secret update"); err != nil {
|
||||
return err
|
||||
}
|
||||
query := url.Values{}
|
||||
query.Set("version", version.String())
|
||||
resp, err := cli.post(ctx, "/secrets/"+id+"/update", query, secret, nil)
|
||||
|
||||
@@ -15,13 +15,6 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestSecretUpdateUnsupported(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithVersion("1.24"), WithHTTPClient(&http.Client{}))
|
||||
assert.NilError(t, err)
|
||||
err = client.SecretUpdate(context.Background(), "secret_id", swarm.Version{}, swarm.SecretSpec{})
|
||||
assert.Check(t, is.Error(err, `"secret update" requires API version 1.25, but the Docker daemon API version is 1.24`))
|
||||
}
|
||||
|
||||
func TestSecretUpdateError(t *testing.T) {
|
||||
client, err := NewClientWithOpts(WithVersion("1.25"), WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
|
||||
assert.NilError(t, err)
|
||||
|
||||
@@ -11,10 +11,6 @@ import (
|
||||
|
||||
// VolumesPrune requests the daemon to delete unused data
|
||||
func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) (volume.PruneReport, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.25", "volume prune"); err != nil {
|
||||
return volume.PruneReport{}, err
|
||||
}
|
||||
|
||||
query, err := getFiltersQuery(pruneFilters)
|
||||
if err != nil {
|
||||
return volume.PruneReport{}, err
|
||||
|
||||
@@ -15,9 +15,6 @@ func (cli *Client) VolumeUpdate(ctx context.Context, volumeID string, version sw
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.42", "volume update"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("version", version.String())
|
||||
|
||||
@@ -32,7 +32,7 @@ func (br *buildRouter) Routes() []router.Route {
|
||||
func (br *buildRouter) initRoutes() {
|
||||
br.routes = []router.Route{
|
||||
router.NewPostRoute("/build", br.postBuild),
|
||||
router.NewPostRoute("/build/prune", br.postPrune),
|
||||
router.NewPostRoute("/build/prune", br.postPrune, router.WithMinimumAPIVersion("1.31")),
|
||||
router.NewPostRoute("/build/cancel", br.postCancel),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ func (c *containerRouter) initRoutes() {
|
||||
router.NewPostRoute("/exec/{name:.*}/resize", c.postContainerExecResize),
|
||||
router.NewPostRoute("/containers/{name:.*}/rename", c.postContainerRename),
|
||||
router.NewPostRoute("/containers/{name:.*}/update", c.postContainerUpdate),
|
||||
router.NewPostRoute("/containers/prune", c.postContainersPrune),
|
||||
router.NewPostRoute("/containers/prune", c.postContainersPrune, router.WithMinimumAPIVersion("1.25")),
|
||||
router.NewPostRoute("/commit", c.postCommit),
|
||||
// PUT
|
||||
router.NewPutRoute("/containers/{name:.*}/archive", c.putContainersArchive),
|
||||
|
||||
@@ -26,6 +26,6 @@ func (dr *distributionRouter) Routes() []router.Route {
|
||||
func (dr *distributionRouter) initRoutes() {
|
||||
dr.routes = []router.Route{
|
||||
// GET
|
||||
router.NewGetRoute("/distribution/{name:.*}/json", dr.getDistributionInfo),
|
||||
router.NewGetRoute("/distribution/{name:.*}/json", dr.getDistributionInfo, router.WithMinimumAPIVersion("1.30")),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ func (ir *imageRouter) initRoutes() {
|
||||
router.NewPostRoute("/images/create", ir.postImagesCreate),
|
||||
router.NewPostRoute("/images/{name:.*}/push", ir.postImagesPush),
|
||||
router.NewPostRoute("/images/{name:.*}/tag", ir.postImagesTag),
|
||||
router.NewPostRoute("/images/prune", ir.postImagesPrune),
|
||||
router.NewPostRoute("/images/prune", ir.postImagesPrune, router.WithMinimumAPIVersion("1.25")),
|
||||
// DELETE
|
||||
router.NewDeleteRoute("/images/{name:.*}", ir.deleteImages),
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/moby/moby/api/types/versions"
|
||||
"github.com/moby/moby/v2/daemon/server/httputils"
|
||||
)
|
||||
|
||||
@@ -71,3 +73,32 @@ func NewOptionsRoute(path string, handler httputils.APIFunc, opts ...RouteWrappe
|
||||
func NewHeadRoute(path string, handler httputils.APIFunc, opts ...RouteWrapper) Route {
|
||||
return NewRoute(http.MethodHead, path, handler, opts...)
|
||||
}
|
||||
|
||||
// WithMinimumAPIVersion configures the minimum API version required for
|
||||
// a route. It produces a 400 (Invalid Request) error when accessing the
|
||||
// endpoint on API versions lower than "minAPIVersion".
|
||||
//
|
||||
// Note that technically, it should produce a 404 ("not found") error,
|
||||
// as the endpoint should be considered "non-existing" on such API versions,
|
||||
// but 404 status-codes are used in business logic for various endpoints.
|
||||
func WithMinimumAPIVersion(minAPIVersion string) RouteWrapper {
|
||||
return func(route Route) Route {
|
||||
return localRoute{
|
||||
method: route.Method(),
|
||||
path: route.Path(),
|
||||
handler: func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if v := httputils.VersionFromContext(ctx); v != "" && versions.LessThan(v, minAPIVersion) {
|
||||
return versionError(route.Method() + " " + route.Path() + " requires minimum API version " + minAPIVersion)
|
||||
}
|
||||
return route.Handler()(ctx, w, r, vars)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type versionError string
|
||||
|
||||
func (e versionError) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
func (e versionError) InvalidParameter() {}
|
||||
|
||||
@@ -36,7 +36,7 @@ func (n *networkRouter) initRoutes() {
|
||||
router.NewPostRoute("/networks/create", n.postNetworkCreate),
|
||||
router.NewPostRoute("/networks/{id:.*}/connect", n.postNetworkConnect),
|
||||
router.NewPostRoute("/networks/{id:.*}/disconnect", n.postNetworkDisconnect),
|
||||
router.NewPostRoute("/networks/prune", n.postNetworksPrune),
|
||||
router.NewPostRoute("/networks/prune", n.postNetworksPrune, router.WithMinimumAPIVersion("1.25")),
|
||||
// DELETE
|
||||
router.NewDeleteRoute("/networks/{id:.*}", n.deleteNetwork),
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ func (pr *pluginRouter) initRoutes() {
|
||||
router.NewPostRoute("/plugins/{name:.*}/disable", pr.disablePlugin),
|
||||
router.NewPostRoute("/plugins/pull", pr.pullPlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/push", pr.pushPlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/upgrade", pr.upgradePlugin),
|
||||
router.NewPostRoute("/plugins/{name:.*}/upgrade", pr.upgradePlugin, router.WithMinimumAPIVersion("1.26")),
|
||||
router.NewPostRoute("/plugins/{name:.*}/set", pr.setPlugin),
|
||||
router.NewPostRoute("/plugins/create", pr.createPlugin),
|
||||
}
|
||||
|
||||
@@ -48,16 +48,16 @@ func (sr *swarmRouter) initRoutes() {
|
||||
router.NewGetRoute("/tasks/{id}", sr.getTask),
|
||||
router.NewGetRoute("/tasks/{id}/logs", sr.getTaskLogs),
|
||||
|
||||
router.NewGetRoute("/secrets", sr.getSecrets),
|
||||
router.NewPostRoute("/secrets/create", sr.createSecret),
|
||||
router.NewDeleteRoute("/secrets/{id}", sr.removeSecret),
|
||||
router.NewGetRoute("/secrets/{id}", sr.getSecret),
|
||||
router.NewPostRoute("/secrets/{id}/update", sr.updateSecret),
|
||||
router.NewGetRoute("/secrets", sr.getSecrets, router.WithMinimumAPIVersion("1.25")),
|
||||
router.NewPostRoute("/secrets/create", sr.createSecret, router.WithMinimumAPIVersion("1.25")),
|
||||
router.NewDeleteRoute("/secrets/{id}", sr.removeSecret, router.WithMinimumAPIVersion("1.25")),
|
||||
router.NewGetRoute("/secrets/{id}", sr.getSecret, router.WithMinimumAPIVersion("1.25")),
|
||||
router.NewPostRoute("/secrets/{id}/update", sr.updateSecret, router.WithMinimumAPIVersion("1.25")),
|
||||
|
||||
router.NewGetRoute("/configs", sr.getConfigs),
|
||||
router.NewPostRoute("/configs/create", sr.createConfig),
|
||||
router.NewDeleteRoute("/configs/{id}", sr.removeConfig),
|
||||
router.NewGetRoute("/configs/{id}", sr.getConfig),
|
||||
router.NewPostRoute("/configs/{id}/update", sr.updateConfig),
|
||||
router.NewGetRoute("/configs", sr.getConfigs, router.WithMinimumAPIVersion("1.30")),
|
||||
router.NewPostRoute("/configs/create", sr.createConfig, router.WithMinimumAPIVersion("1.30")),
|
||||
router.NewDeleteRoute("/configs/{id}", sr.removeConfig, router.WithMinimumAPIVersion("1.30")),
|
||||
router.NewGetRoute("/configs/{id}", sr.getConfig, router.WithMinimumAPIVersion("1.30")),
|
||||
router.NewPostRoute("/configs/{id}/update", sr.updateConfig, router.WithMinimumAPIVersion("1.30")),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,9 +31,9 @@ func (v *volumeRouter) initRoutes() {
|
||||
router.NewGetRoute("/volumes/{name:.*}", v.getVolumeByName),
|
||||
// POST
|
||||
router.NewPostRoute("/volumes/create", v.postVolumesCreate),
|
||||
router.NewPostRoute("/volumes/prune", v.postVolumesPrune),
|
||||
router.NewPostRoute("/volumes/prune", v.postVolumesPrune, router.WithMinimumAPIVersion("1.25")),
|
||||
// PUT
|
||||
router.NewPutRoute("/volumes/{name:.*}", v.putVolumesUpdate),
|
||||
router.NewPutRoute("/volumes/{name:.*}", v.putVolumesUpdate, router.WithMinimumAPIVersion("1.42")),
|
||||
// DELETE
|
||||
router.NewDeleteRoute("/volumes/{name:.*}", v.deleteVolumes),
|
||||
}
|
||||
|
||||
4
vendor/github.com/moby/moby/client/build_prune.go
generated
vendored
4
vendor/github.com/moby/moby/client/build_prune.go
generated
vendored
@@ -23,10 +23,6 @@ type BuildCachePruneOptions struct {
|
||||
|
||||
// BuildCachePrune requests the daemon to delete unused cache data.
|
||||
func (cli *Client) BuildCachePrune(ctx context.Context, opts BuildCachePruneOptions) (*build.CachePruneReport, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.31", "build prune"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
if opts.All {
|
||||
query.Set("all", "1")
|
||||
|
||||
7
vendor/github.com/moby/moby/client/config_create.go
generated
vendored
7
vendor/github.com/moby/moby/client/config_create.go
generated
vendored
@@ -9,16 +9,13 @@ import (
|
||||
|
||||
// ConfigCreate creates a new config.
|
||||
func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
|
||||
var response swarm.ConfigCreateResponse
|
||||
if err := cli.NewVersionError(ctx, "1.30", "config create"); err != nil {
|
||||
return response, err
|
||||
}
|
||||
resp, err := cli.post(ctx, "/configs/create", nil, config, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
return response, err
|
||||
return swarm.ConfigCreateResponse{}, err
|
||||
}
|
||||
|
||||
var response swarm.ConfigCreateResponse
|
||||
err = json.NewDecoder(resp.Body).Decode(&response)
|
||||
return response, err
|
||||
}
|
||||
|
||||
3
vendor/github.com/moby/moby/client/config_inspect.go
generated
vendored
3
vendor/github.com/moby/moby/client/config_inspect.go
generated
vendored
@@ -15,9 +15,6 @@ func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.C
|
||||
if err != nil {
|
||||
return swarm.Config{}, nil, err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.30", "config inspect"); err != nil {
|
||||
return swarm.Config{}, nil, err
|
||||
}
|
||||
resp, err := cli.get(ctx, "/configs/"+id, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
|
||||
3
vendor/github.com/moby/moby/client/config_list.go
generated
vendored
3
vendor/github.com/moby/moby/client/config_list.go
generated
vendored
@@ -11,9 +11,6 @@ import (
|
||||
|
||||
// ConfigList returns the list of configs.
|
||||
func (cli *Client) ConfigList(ctx context.Context, options ConfigListOptions) ([]swarm.Config, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.30", "config list"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query := url.Values{}
|
||||
|
||||
if options.Filters.Len() > 0 {
|
||||
|
||||
3
vendor/github.com/moby/moby/client/config_remove.go
generated
vendored
3
vendor/github.com/moby/moby/client/config_remove.go
generated
vendored
@@ -8,9 +8,6 @@ func (cli *Client) ConfigRemove(ctx context.Context, id string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.30", "config remove"); err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := cli.delete(ctx, "/configs/"+id, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
|
||||
3
vendor/github.com/moby/moby/client/config_update.go
generated
vendored
3
vendor/github.com/moby/moby/client/config_update.go
generated
vendored
@@ -13,9 +13,6 @@ func (cli *Client) ConfigUpdate(ctx context.Context, id string, version swarm.Ve
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.30", "config update"); err != nil {
|
||||
return err
|
||||
}
|
||||
query := url.Values{}
|
||||
query.Set("version", version.String())
|
||||
resp, err := cli.post(ctx, "/configs/"+id+"/update", query, config, nil)
|
||||
|
||||
4
vendor/github.com/moby/moby/client/container_prune.go
generated
vendored
4
vendor/github.com/moby/moby/client/container_prune.go
generated
vendored
@@ -11,10 +11,6 @@ import (
|
||||
|
||||
// ContainersPrune requests the daemon to delete unused data
|
||||
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.25", "container prune"); err != nil {
|
||||
return container.PruneReport{}, err
|
||||
}
|
||||
|
||||
query, err := getFiltersQuery(pruneFilters)
|
||||
if err != nil {
|
||||
return container.PruneReport{}, err
|
||||
|
||||
4
vendor/github.com/moby/moby/client/distribution_inspect.go
generated
vendored
4
vendor/github.com/moby/moby/client/distribution_inspect.go
generated
vendored
@@ -15,10 +15,6 @@ func (cli *Client) DistributionInspect(ctx context.Context, imageRef, encodedReg
|
||||
return registry.DistributionInspect{}, objectNotFoundError{object: "distribution", id: imageRef}
|
||||
}
|
||||
|
||||
if err := cli.NewVersionError(ctx, "1.30", "distribution inspect"); err != nil {
|
||||
return registry.DistributionInspect{}, err
|
||||
}
|
||||
|
||||
var headers http.Header
|
||||
if encodedRegistryAuth != "" {
|
||||
headers = http.Header{
|
||||
|
||||
4
vendor/github.com/moby/moby/client/image_prune.go
generated
vendored
4
vendor/github.com/moby/moby/client/image_prune.go
generated
vendored
@@ -11,10 +11,6 @@ import (
|
||||
|
||||
// ImagesPrune requests the daemon to delete unused data
|
||||
func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (image.PruneReport, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.25", "image prune"); err != nil {
|
||||
return image.PruneReport{}, err
|
||||
}
|
||||
|
||||
query, err := getFiltersQuery(pruneFilters)
|
||||
if err != nil {
|
||||
return image.PruneReport{}, err
|
||||
|
||||
4
vendor/github.com/moby/moby/client/network_prune.go
generated
vendored
4
vendor/github.com/moby/moby/client/network_prune.go
generated
vendored
@@ -11,10 +11,6 @@ import (
|
||||
|
||||
// NetworksPrune requests the daemon to delete unused networks
|
||||
func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (network.PruneReport, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.25", "network prune"); err != nil {
|
||||
return network.PruneReport{}, err
|
||||
}
|
||||
|
||||
query, err := getFiltersQuery(pruneFilters)
|
||||
if err != nil {
|
||||
return network.PruneReport{}, err
|
||||
|
||||
3
vendor/github.com/moby/moby/client/plugin_upgrade.go
generated
vendored
3
vendor/github.com/moby/moby/client/plugin_upgrade.go
generated
vendored
@@ -19,9 +19,6 @@ func (cli *Client) PluginUpgrade(ctx context.Context, name string, options Plugi
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := cli.NewVersionError(ctx, "1.26", "plugin upgrade"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query := url.Values{}
|
||||
if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
|
||||
return nil, fmt.Errorf("invalid remote reference: %w", err)
|
||||
|
||||
3
vendor/github.com/moby/moby/client/secret_create.go
generated
vendored
3
vendor/github.com/moby/moby/client/secret_create.go
generated
vendored
@@ -9,9 +9,6 @@ import (
|
||||
|
||||
// SecretCreate creates a new secret.
|
||||
func (cli *Client) SecretCreate(ctx context.Context, secret swarm.SecretSpec) (swarm.SecretCreateResponse, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.25", "secret create"); err != nil {
|
||||
return swarm.SecretCreateResponse{}, err
|
||||
}
|
||||
resp, err := cli.post(ctx, "/secrets/create", nil, secret, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
|
||||
3
vendor/github.com/moby/moby/client/secret_inspect.go
generated
vendored
3
vendor/github.com/moby/moby/client/secret_inspect.go
generated
vendored
@@ -15,9 +15,6 @@ func (cli *Client) SecretInspectWithRaw(ctx context.Context, id string) (swarm.S
|
||||
if err != nil {
|
||||
return swarm.Secret{}, nil, err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.25", "secret inspect"); err != nil {
|
||||
return swarm.Secret{}, nil, err
|
||||
}
|
||||
resp, err := cli.get(ctx, "/secrets/"+id, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
if err != nil {
|
||||
|
||||
3
vendor/github.com/moby/moby/client/secret_list.go
generated
vendored
3
vendor/github.com/moby/moby/client/secret_list.go
generated
vendored
@@ -11,9 +11,6 @@ import (
|
||||
|
||||
// SecretList returns the list of secrets.
|
||||
func (cli *Client) SecretList(ctx context.Context, options SecretListOptions) ([]swarm.Secret, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.25", "secret list"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query := url.Values{}
|
||||
|
||||
if options.Filters.Len() > 0 {
|
||||
|
||||
3
vendor/github.com/moby/moby/client/secret_remove.go
generated
vendored
3
vendor/github.com/moby/moby/client/secret_remove.go
generated
vendored
@@ -8,9 +8,6 @@ func (cli *Client) SecretRemove(ctx context.Context, id string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.25", "secret remove"); err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := cli.delete(ctx, "/secrets/"+id, nil, nil)
|
||||
defer ensureReaderClosed(resp)
|
||||
return err
|
||||
|
||||
3
vendor/github.com/moby/moby/client/secret_update.go
generated
vendored
3
vendor/github.com/moby/moby/client/secret_update.go
generated
vendored
@@ -13,9 +13,6 @@ func (cli *Client) SecretUpdate(ctx context.Context, id string, version swarm.Ve
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.25", "secret update"); err != nil {
|
||||
return err
|
||||
}
|
||||
query := url.Values{}
|
||||
query.Set("version", version.String())
|
||||
resp, err := cli.post(ctx, "/secrets/"+id+"/update", query, secret, nil)
|
||||
|
||||
4
vendor/github.com/moby/moby/client/volume_prune.go
generated
vendored
4
vendor/github.com/moby/moby/client/volume_prune.go
generated
vendored
@@ -11,10 +11,6 @@ import (
|
||||
|
||||
// VolumesPrune requests the daemon to delete unused data
|
||||
func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) (volume.PruneReport, error) {
|
||||
if err := cli.NewVersionError(ctx, "1.25", "volume prune"); err != nil {
|
||||
return volume.PruneReport{}, err
|
||||
}
|
||||
|
||||
query, err := getFiltersQuery(pruneFilters)
|
||||
if err != nil {
|
||||
return volume.PruneReport{}, err
|
||||
|
||||
3
vendor/github.com/moby/moby/client/volume_update.go
generated
vendored
3
vendor/github.com/moby/moby/client/volume_update.go
generated
vendored
@@ -15,9 +15,6 @@ func (cli *Client) VolumeUpdate(ctx context.Context, volumeID string, version sw
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cli.NewVersionError(ctx, "1.42", "volume update"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("version", version.String())
|
||||
|
||||
Reference in New Issue
Block a user