From 3ca29823d42ab1e2b1ea76981ccc9aa11e858cb2 Mon Sep 17 00:00:00 2001 From: David Calavera Date: Mon, 28 Mar 2016 13:41:06 -0400 Subject: [PATCH 1/2] Remove runconfig dependency from network routes. Signed-off-by: David Calavera --- api/server/router/network/backend.go | 6 +- api/server/router/network/network_routes.go | 37 ++----------- daemon/network.go | 55 ++++++++++++++++--- .../router => daemon}/network/filter.go | 6 +- integration-cli/docker_api_network_test.go | 2 +- 5 files changed, 58 insertions(+), 48 deletions(-) rename {api/server/router => daemon}/network/filter.go (93%) diff --git a/api/server/router/network/backend.go b/api/server/router/network/backend.go index 7bbbca4ddd..bf5af0625f 100644 --- a/api/server/router/network/backend.go +++ b/api/server/router/network/backend.go @@ -1,6 +1,8 @@ package network import ( + "github.com/docker/engine-api/types" + "github.com/docker/engine-api/types/filters" "github.com/docker/engine-api/types/network" "github.com/docker/libnetwork" ) @@ -11,8 +13,8 @@ type Backend interface { FindNetwork(idName string) (libnetwork.Network, error) GetNetworkByName(idName string) (libnetwork.Network, error) GetNetworksByID(partialID string) []libnetwork.Network - GetAllNetworks() []libnetwork.Network - CreateNetwork(name, driver string, ipam network.IPAM, options map[string]string, labels map[string]string, internal bool, enableIPv6 bool) (libnetwork.Network, error) + FilterNetworks(netFilters filters.Args) ([]libnetwork.Network, error) + CreateNetwork(types.NetworkCreate) (*types.NetworkCreateResponse, error) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error DisconnectContainerFromNetwork(containerName string, network libnetwork.Network, force bool) error DeleteNetwork(name string) error diff --git a/api/server/router/network/network_routes.go b/api/server/router/network/network_routes.go index f052f54118..dd4a28f3a5 100644 --- a/api/server/router/network/network_routes.go +++ b/api/server/router/network/network_routes.go @@ -2,13 +2,11 @@ package network import ( "encoding/json" - "fmt" "net/http" "golang.org/x/net/context" "github.com/docker/docker/api/server/httputils" - "github.com/docker/docker/runconfig" "github.com/docker/engine-api/types" "github.com/docker/engine-api/types/filters" "github.com/docker/engine-api/types/network" @@ -26,21 +24,14 @@ func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWrit return err } - if netFilters.Len() != 0 { - if err := netFilters.Validate(acceptedFilters); err != nil { - return err - } - } - list := []*types.NetworkResource{} - nwList := n.backend.GetAllNetworks() - displayable, err := filterNetworks(nwList, netFilters) + nwList, err := n.backend.FilterNetworks(netFilters) if err != nil { return err } - for _, nw := range displayable { + for _, nw := range nwList { list = append(list, buildNetworkResource(nw)) } @@ -61,7 +52,6 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var create types.NetworkCreate - var warning string if err := httputils.ParseForm(r); err != nil { return err @@ -75,31 +65,12 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr return err } - if runconfig.IsPreDefinedNetwork(create.Name) { - return httputils.WriteJSON(w, http.StatusForbidden, - fmt.Sprintf("%s is a pre-defined network and cannot be created", create.Name)) - } - - nw, err := n.backend.GetNetworkByName(create.Name) - if _, ok := err.(libnetwork.ErrNoSuchNetwork); err != nil && !ok { - return err - } - if nw != nil { - if create.CheckDuplicate { - return libnetwork.NetworkNameError(create.Name) - } - warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID()) - } - - nw, err = n.backend.CreateNetwork(create.Name, create.Driver, create.IPAM, create.Options, create.Labels, create.Internal, create.EnableIPv6) + nw, err := n.backend.CreateNetwork(create) if err != nil { return err } - return httputils.WriteJSON(w, http.StatusCreated, &types.NetworkCreateResponse{ - ID: nw.ID(), - Warning: warning, - }) + return httputils.WriteJSON(w, http.StatusCreated, nw) } func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { diff --git a/daemon/network.go b/daemon/network.go index 98879915da..d916888514 100644 --- a/daemon/network.go +++ b/daemon/network.go @@ -6,8 +6,11 @@ import ( "net/http" "strings" + netsettings "github.com/docker/docker/daemon/network" "github.com/docker/docker/errors" "github.com/docker/docker/runconfig" + "github.com/docker/engine-api/types" + "github.com/docker/engine-api/types/filters" "github.com/docker/engine-api/types/network" "github.com/docker/libnetwork" ) @@ -77,8 +80,8 @@ func (daemon *Daemon) GetNetworksByID(partialID string) []libnetwork.Network { return list } -// GetAllNetworks returns a list containing all networks -func (daemon *Daemon) GetAllNetworks() []libnetwork.Network { +// getAllNetworks returns a list containing all networks +func (daemon *Daemon) getAllNetworks() []libnetwork.Network { c := daemon.netController list := []libnetwork.Network{} l := func(nw libnetwork.Network) bool { @@ -91,12 +94,33 @@ func (daemon *Daemon) GetAllNetworks() []libnetwork.Network { } // CreateNetwork creates a network with the given name, driver and other optional parameters -func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, netOption map[string]string, labels map[string]string, internal bool, enableIPv6 bool) (libnetwork.Network, error) { +func (daemon *Daemon) CreateNetwork(create types.NetworkCreate) (*types.NetworkCreateResponse, error) { + if runconfig.IsPreDefinedNetwork(create.Name) { + err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name) + return nil, errors.NewErrorWithStatusCode(err, http.StatusForbidden) + } + + var warning string + nw, err := daemon.GetNetworkByName(create.Name) + if err != nil { + if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok { + return nil, err + } + } + if nw != nil { + if create.CheckDuplicate { + return nil, libnetwork.NetworkNameError(create.Name) + } + warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID()) + } + c := daemon.netController + driver := create.Driver if driver == "" { driver = c.Config().Daemon.DefaultDriver } + ipam := create.IPAM v4Conf, v6Conf, err := getIpamConfig(ipam.Config) if err != nil { return nil, err @@ -104,20 +128,23 @@ func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, netO nwOptions := []libnetwork.NetworkOption{ libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options), - libnetwork.NetworkOptionEnableIPv6(enableIPv6), - libnetwork.NetworkOptionDriverOpts(netOption), - libnetwork.NetworkOptionLabels(labels), + libnetwork.NetworkOptionEnableIPv6(create.EnableIPv6), + libnetwork.NetworkOptionDriverOpts(create.Options), + libnetwork.NetworkOptionLabels(create.Labels), } - if internal { + if create.Internal { nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork()) } - n, err := c.NewNetwork(driver, name, nwOptions...) + n, err := c.NewNetwork(driver, create.Name, nwOptions...) if err != nil { return nil, err } daemon.LogNetworkEvent(n, "create") - return n, nil + return &types.NetworkCreateResponse{ + ID: n.ID(), + Warning: warning, + }, nil } func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) { @@ -203,3 +230,13 @@ func (daemon *Daemon) DeleteNetwork(networkID string) error { daemon.LogNetworkEvent(nw, "destroy") return nil } + +func (daemon *Daemon) FilterNetworks(netFilters filters.Args) ([]libnetwork.Network, error) { + if netFilters.Len() != 0 { + if err := netFilters.Validate(netsettings.AcceptedFilters); err != nil { + return nil, err + } + } + nwList := daemon.getAllNetworks() + return netsettings.FilterNetworks(nwList, netFilters) +} diff --git a/api/server/router/network/filter.go b/daemon/network/filter.go similarity index 93% rename from api/server/router/network/filter.go rename to daemon/network/filter.go index f1648cc2ae..0b4ffa971d 100644 --- a/api/server/router/network/filter.go +++ b/daemon/network/filter.go @@ -27,7 +27,7 @@ var ( // "name": true, // "id": true, // } - acceptedFilters = func() map[string]bool { + AcceptedFilters = func() map[string]bool { ret := make(map[string]bool) for k := range supportedFilters { ret[k] = true @@ -84,9 +84,9 @@ func filterNetworkByID(nws []libnetwork.Network, id string) (retNws []libnetwork return retNws, nil } -// filterAllNetworks filters network list according to user specified filter +// FilterAllNetworks filters network list according to user specified filter // and returns user chosen networks -func filterNetworks(nws []libnetwork.Network, filter filters.Args) ([]libnetwork.Network, error) { +func FilterNetworks(nws []libnetwork.Network, filter filters.Args) ([]libnetwork.Network, error) { // if filter is empty, return original network list if filter.Len() == 0 { return nws, nil diff --git a/integration-cli/docker_api_network_test.go b/integration-cli/docker_api_network_test.go index e65c7b5ee5..b11803f9b9 100644 --- a/integration-cli/docker_api_network_test.go +++ b/integration-cli/docker_api_network_test.go @@ -296,8 +296,8 @@ func createNetwork(c *check.C, config types.NetworkCreate, shouldSucceed bool) s return "" } - c.Assert(status, checker.Equals, http.StatusCreated) c.Assert(err, checker.IsNil) + c.Assert(status, checker.Equals, http.StatusCreated) var nr types.NetworkCreateResponse err = json.Unmarshal(resp, &nr) From f0d26e1665f7552972db5b041554cc7b45bc3060 Mon Sep 17 00:00:00 2001 From: David Calavera Date: Mon, 28 Mar 2016 14:22:23 -0400 Subject: [PATCH 2/2] Remove runconfig package dependency from image and container routers. Use an interface to specify the behavior of a configuration decoder. Signed-off-by: David Calavera --- api/server/httputils/decoder.go | 16 ++++++++++++++++ api/server/router/container/container.go | 9 +++++++-- api/server/router/container/container_routes.go | 5 ++--- api/server/router/image/image.go | 9 +++++++-- api/server/router/image/image_routes.go | 3 +-- daemon/network.go | 2 ++ daemon/network/filter.go | 4 ++-- docker/daemon.go | 7 +++++-- runconfig/config.go | 14 ++++++++++++++ 9 files changed, 56 insertions(+), 13 deletions(-) create mode 100644 api/server/httputils/decoder.go diff --git a/api/server/httputils/decoder.go b/api/server/httputils/decoder.go new file mode 100644 index 0000000000..dbe469cca6 --- /dev/null +++ b/api/server/httputils/decoder.go @@ -0,0 +1,16 @@ +package httputils + +import ( + "io" + + "github.com/docker/engine-api/types/container" + "github.com/docker/engine-api/types/network" +) + +// ContainerDecoder specifies how +// to translate an io.Reader into +// container configuration. +type ContainerDecoder interface { + DecodeConfig(src io.Reader) (*container.Config, *container.HostConfig, *network.NetworkingConfig, error) + DecodeHostConfig(src io.Reader) (*container.HostConfig, error) +} diff --git a/api/server/router/container/container.go b/api/server/router/container/container.go index 873f13d295..68313bfd39 100644 --- a/api/server/router/container/container.go +++ b/api/server/router/container/container.go @@ -1,17 +1,22 @@ package container -import "github.com/docker/docker/api/server/router" +import ( + "github.com/docker/docker/api/server/httputils" + "github.com/docker/docker/api/server/router" +) // containerRouter is a router to talk with the container controller type containerRouter struct { backend Backend + decoder httputils.ContainerDecoder routes []router.Route } // NewRouter initializes a new container router -func NewRouter(b Backend) router.Router { +func NewRouter(b Backend, decoder httputils.ContainerDecoder) router.Router { r := &containerRouter{ backend: b, + decoder: decoder, } r.initRoutes() return r diff --git a/api/server/router/container/container_routes.go b/api/server/router/container/container_routes.go index 016e00f05b..e029b63adf 100644 --- a/api/server/router/container/container_routes.go +++ b/api/server/router/container/container_routes.go @@ -16,7 +16,6 @@ import ( "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/term" - "github.com/docker/docker/runconfig" "github.com/docker/engine-api/types" "github.com/docker/engine-api/types/container" "github.com/docker/engine-api/types/filters" @@ -149,7 +148,7 @@ func (s *containerRouter) postContainersStart(ctx context.Context, w http.Respon return err } - c, err := runconfig.DecodeHostConfig(r.Body) + c, err := s.decoder.DecodeHostConfig(r.Body) if err != nil { return err } @@ -350,7 +349,7 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo name := r.Form.Get("name") - config, hostConfig, networkingConfig, err := runconfig.DecodeContainerConfig(r.Body) + config, hostConfig, networkingConfig, err := s.decoder.DecodeConfig(r.Body) if err != nil { return err } diff --git a/api/server/router/image/image.go b/api/server/router/image/image.go index d6a1297a97..f0235a53be 100644 --- a/api/server/router/image/image.go +++ b/api/server/router/image/image.go @@ -1,17 +1,22 @@ package image -import "github.com/docker/docker/api/server/router" +import ( + "github.com/docker/docker/api/server/httputils" + "github.com/docker/docker/api/server/router" +) // imageRouter is a router to talk with the image controller type imageRouter struct { backend Backend + decoder httputils.ContainerDecoder routes []router.Route } // NewRouter initializes a new image router -func NewRouter(backend Backend) router.Router { +func NewRouter(backend Backend, decoder httputils.ContainerDecoder) router.Router { r := &imageRouter{ backend: backend, + decoder: decoder, } r.initRoutes() return r diff --git a/api/server/router/image/image_routes.go b/api/server/router/image/image_routes.go index e0c4c70215..b1db315fd2 100644 --- a/api/server/router/image/image_routes.go +++ b/api/server/router/image/image_routes.go @@ -17,7 +17,6 @@ import ( "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/streamformatter" "github.com/docker/docker/reference" - "github.com/docker/docker/runconfig" "github.com/docker/engine-api/types" "github.com/docker/engine-api/types/container" "golang.org/x/net/context" @@ -40,7 +39,7 @@ func (s *imageRouter) postCommit(ctx context.Context, w http.ResponseWriter, r * pause = true } - c, _, _, err := runconfig.DecodeContainerConfig(r.Body) + c, _, _, err := s.decoder.DecodeConfig(r.Body) if err != nil && err != io.EOF { //Do not fail if body is empty. return err } diff --git a/daemon/network.go b/daemon/network.go index d916888514..a9338d1252 100644 --- a/daemon/network.go +++ b/daemon/network.go @@ -231,6 +231,8 @@ func (daemon *Daemon) DeleteNetwork(networkID string) error { return nil } +// FilterNetworks returns a list of networks filtered by the given arguments. +// It returns an error if the filters are not included in the list of accepted filters. func (daemon *Daemon) FilterNetworks(netFilters filters.Args) ([]libnetwork.Network, error) { if netFilters.Len() != 0 { if err := netFilters.Validate(netsettings.AcceptedFilters); err != nil { diff --git a/daemon/network/filter.go b/daemon/network/filter.go index 0b4ffa971d..893f707f7b 100644 --- a/daemon/network/filter.go +++ b/daemon/network/filter.go @@ -20,7 +20,7 @@ var ( "id": filterNetworkByID, } - // acceptFilters is an acceptable filter flag list + // AcceptedFilters is an acceptable filter flag list // generated for validation. e.g. // acceptedFilters = map[string]bool{ // "type": true, @@ -84,7 +84,7 @@ func filterNetworkByID(nws []libnetwork.Network, id string) (retNws []libnetwork return retNws, nil } -// FilterAllNetworks filters network list according to user specified filter +// FilterNetworks filters network list according to user specified filter // and returns user chosen networks func FilterNetworks(nws []libnetwork.Network, filter filters.Args) ([]libnetwork.Network, error) { // if filter is empty, return original network list diff --git a/docker/daemon.go b/docker/daemon.go index c25a51e345..7afe8e4249 100644 --- a/docker/daemon.go +++ b/docker/daemon.go @@ -37,6 +37,7 @@ import ( "github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/system" "github.com/docker/docker/registry" + "github.com/docker/docker/runconfig" "github.com/docker/docker/utils" "github.com/docker/go-connections/tlsconfig" ) @@ -405,9 +406,11 @@ func loadDaemonCliConfig(config *daemon.Config, daemonFlags *flag.FlagSet, commo } func initRouter(s *apiserver.Server, d *daemon.Daemon) { + decoder := runconfig.ContainerDecoder{} + routers := []router.Router{ - container.NewRouter(d), - image.NewRouter(d), + container.NewRouter(d, decoder), + image.NewRouter(d, decoder), systemrouter.NewRouter(d), volume.NewRouter(d), build.NewRouter(dockerfile.NewBuildManager(d)), diff --git a/runconfig/config.go b/runconfig/config.go index 9f3f9c5e63..5391e30078 100644 --- a/runconfig/config.go +++ b/runconfig/config.go @@ -10,6 +10,20 @@ import ( networktypes "github.com/docker/engine-api/types/network" ) +// ContainerDecoder implements httputils.ContainerDecoder +// calling DecodeContainerConfig. +type ContainerDecoder struct{} + +// DecodeConfig makes ContainerDecoder to implement httputils.ContainerDecoder +func (r ContainerDecoder) DecodeConfig(src io.Reader) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) { + return DecodeContainerConfig(src) +} + +// DecodeHostConfig makes ContainerDecoder to implement httputils.ContainerDecoder +func (r ContainerDecoder) DecodeHostConfig(src io.Reader) (*container.HostConfig, error) { + return DecodeHostConfig(src) +} + // DecodeContainerConfig decodes a json encoded config into a ContainerConfigWrapper // struct and returns both a Config and an HostConfig struct // Be aware this function is not checking whether the resulted structs are nil,