Make invalid states unrepresentable by moving away from stringly-typed
MAC address values in API structs. As go.dev/issue/29678 has not yet
been implemented, provide our own HardwareAddr byte-slice type which
implements TextMarshaler and TextUnmarshaler to retain compatibility
with the API wire format.
When stdlib's net.HardwareAddr type implements TextMarshaler and
TextUnmarshaler and GODEBUG=netmarshal becomes the default, we should be
able to make the type a straight alias for stdlib net.HardwareAddr as a
non-breaking change.
Signed-off-by: Cory Snider <csnider@mirantis.com>
There also appeared to be duplication between daemon.getInspectData,
and the containerRouter.postContainersCreate methods, as both were
back-filling the field.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This field was deprecated in [engine-api@5c4b684], which got vendored into
Moby in [moby@8f7a8c7] (API v1.25), and wired up in [moby@99a98cc].
[engine-api@5c4b684]: 5c4b684b2f
[moby@8f7a8c7]: 8f7a8c75ae
[moby@99a98cc]: 99a98ccc14
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Most of the code in the filters package relates to the unmarshaling,
validation and application of filters from client requests. None of this
is necessary or particularly useful for Go SDK users. Move the full-fat
filters package into daemon/internal and switch all the daemon code to
import that package so we are free to iterate upon the code without
worrying about source-code interface compatibility.
Signed-off-by: Cory Snider <csnider@mirantis.com>
These utilities are very handy to use in integration tests, too. Move
the package so it can be imported by them.
Signed-off-by: Cory Snider <csnider@mirantis.com>
Change the types for IP address and prefix struct fields to netip.Addr
and netip.Prefix for convenience. Fields such as
swarm.InitRequest.ListenAddr which may encode non-numeric values such as
a network interface name have not been modified.
Signed-off-by: Cory Snider <csnider@mirantis.com>
The PullImage method for the ImageService used positional arguments for its
options, which made it more difficult to introduce new options. This patch
introduces a `PullOptions` struct to specify the options. As part of these
changes, the `platform` option was already adjusted to accept a slice of
platforms, which currently is not supported, but may be in the near future.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
As the Engine API requests may be directed at a non-leader Swarm
manager, the information needs to be tunneled through the Swarm API.
Signed-off-by: Cory Snider <csnider@mirantis.com>
Move the option-types to the client and in some cases create a
copy for the backend. These types are used to construct query-
args, and not marshaled to JSON, and can be replaced with functional
options in the client.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
While the network Summary and Inspect types have been aliases in Go's
type system, in practice there is a difference: the Containers and
Services fields are only populated when inspecting a network. Split out
the common fields into a base network.Network struct which is embedded
in the network.Summary and network.Inspect types.
Signed-off-by: Cory Snider <csnider@mirantis.com>
Filter-term validation does not belong in the API module. Clients should
not be making any assumptions about which terms the daemon understands.
Users should not need to upgrade their clients to use filter terms
introduced in a newer daemon. Move the network filter validation from
the api module into the daemon.
Split network.NewFilter into network.NewListFilter and
network.NewPruneFilter constructors which validate the filter terms,
enforcing the invariant that any network.Filter is a well-formed filter
for networks.
The network route handlers have been leveraging a hidden 'idOrName'
filter term that is not listed in the set of accepted filters and
therefore not accepted in API client requests. And it's a good thing
that it was never part of the API: it is completely broken and not fit
for purpose! When a filter contains an idOrName term, the term values
are ignored and instead the filter tests whether either the 'id' or
'name' terms match the Name of the network. Unless the filter contains
both 'id' and 'name' terms, the match will evaluate to true for all
networks! None of the daemon-internal users of 'idOrName' set either
of those terms, therefore it has the same effect as if the filter did
not contain the 'idOrName' term in the first place.
Filtering networks by id-or-name is a quirky thing that the daemon needs
to do to uphold its end of the Engine API contract, not something that
would be of use to clients. Fixing up the idOrName filter would
necessitate adding it to the list of accepted terms so the filter passes
validaton, which would have the side effect of also making the filter
available to API clients. Instead, add an exported field to the Filter
struct so that daemon code can opt into the internal-only behaviour of
having the 'id' term match on either the network Name or ID.
Signed-off-by: Cory Snider <csnider@mirantis.com>
Construct a network.Filter from the filters.Args only once per API
request so we don't waste cycles re-validating an already validated
filter. Since (*Daemon).NetworksPrune is implemented in terms of
(Cluster).GetNetworks, that method now accepts a network.Filter instead
of a filter.Args. Change the signature of (*Daemon).GetNetworks for
consistency as both of the GetNetworks methods are used by network API
route handlers.
Signed-off-by: Cory Snider <csnider@mirantis.com>
Internally a network is represented by either a libnetwork.Network or a
swarmapi.Network. The daemon functions backing the API server map
these values to the Engine API network.Inspect type on demand. Since
they have to convert, the functions to get a list of networks have to
loop over the slice of Networks and append them to a slice of
network.Inspect values.
The function used to filter the list of networks by a user-supplied
predicate takes a []network.Inspect and returns a shorter slice.
Therefore the daemon functions backing the API server have to loop
through the list twice: once to convert, and again inside the
FilterNetworks function to delete networks from the slice which do not
match the filter predicate. Each time an item is deleted from a slice,
all items at higher indices need to be copied to lower indices in the
backing array to close the hole.
Replace FilterNetworks with a function that accepts a single
interface-valued network and returns a boolean. Amend libnetwork.Network
and write a thin adapter for swarmapi.Network so both implement the
aforementioned interface. The daemon functions can thus filter networks
before projecting the values into API structs, and can completely skip
over non-matching networks, which cuts down on a nontrivial amount of
copying.
Split the validation of the filter predicate from filter evaluation to
both make it more ergonomic to use inside loops, and to make invalid
states (a filter with an ill-formed predicate) unrepresentable.
Signed-off-by: Cory Snider <csnider@mirantis.com>
A few of the cluster methods contained open-coded copies of
lockedManagerAction. Refactor them to use lockedManagerAction and hoist
the parameter and result processing outside the critical sections.
Signed-off-by: Cory Snider <csnider@mirantis.com>
Every Swarm Cluster API method takes a context parameter. The
lockedManagerAction helper function does not take a context parameter
itself, yet it passes a context parameter into the closure. Add a
context parameter to lockedManagerAction and derive the closure's
context from it to afford deriving the Cluster API method calls'
contexts from some non-background parent context.
Signed-off-by: Cory Snider <csnider@mirantis.com>