mirror of
https://github.com/clearlinux/docker.git
synced 2026-09-06 13:41:36 +00:00
Network remote APIs using new router, --net=<user-defined-network> changes
* Moving Network Remote APIs out of experimental * --net can now accept user created networks using network drivers/plugins * Removed the experimental services concept and --default-network option * Neccessary backend changes to accomodate multiple networks per container * Integration Tests Signed-off-by: David Calavera <david.calavera@gmail.com> Signed-off-by: Madhu Venugopal <madhu@docker.com>
This commit is contained in:
@@ -5,11 +5,9 @@ import (
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
dkrouter "github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// router is a docker router that talks with the local docker daemon.
|
||||
@@ -31,11 +29,14 @@ func (l localRoute) Handler() httputils.APIFunc {
|
||||
return l.handler
|
||||
}
|
||||
|
||||
// Register adds the filtered handler to the mux.
|
||||
func (l localRoute) Register(m *mux.Router, handler http.Handler) {
|
||||
logrus.Debugf("Registering %s, %s", l.method, l.path)
|
||||
m.Path(dkrouter.VersionMatcher + l.path).Methods(l.method).Handler(handler)
|
||||
m.Path(l.path).Methods(l.method).Handler(handler)
|
||||
// Method returns the http method that the route responds to.
|
||||
func (l localRoute) Method() string {
|
||||
return l.method
|
||||
}
|
||||
|
||||
// Path returns the subpath where the route responds to.
|
||||
func (l localRoute) Path() string {
|
||||
return l.path
|
||||
}
|
||||
|
||||
// NewRoute initialies a new local route for the reouter
|
||||
|
||||
@@ -1,26 +1,41 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/api/server/router/local"
|
||||
"github.com/docker/docker/daemon"
|
||||
)
|
||||
|
||||
// networkRouter is a router to talk with the network controller
|
||||
type networkRouter struct {
|
||||
daemon *daemon.Daemon
|
||||
routes []router.Route
|
||||
}
|
||||
|
||||
// NewRouter initializes a new network router
|
||||
func NewRouter(d *daemon.Daemon) router.Router {
|
||||
r := &networkRouter{
|
||||
daemon: d,
|
||||
}
|
||||
r.initRoutes()
|
||||
return r
|
||||
}
|
||||
|
||||
// Routes returns the available routes to the network controller
|
||||
func (n networkRouter) Routes() []router.Route {
|
||||
return n.routes
|
||||
func (r *networkRouter) Routes() []router.Route {
|
||||
return r.routes
|
||||
}
|
||||
|
||||
type networkRoute struct {
|
||||
path string
|
||||
handler httputils.APIFunc
|
||||
}
|
||||
|
||||
// Handler returns the APIFunc to let the server wrap it in middlewares
|
||||
func (l networkRoute) Handler() httputils.APIFunc {
|
||||
return l.handler
|
||||
func (r *networkRouter) initRoutes() {
|
||||
r.routes = []router.Route{
|
||||
// GET
|
||||
local.NewGetRoute("/networks", r.getNetworksList),
|
||||
local.NewGetRoute("/networks/{id:.*}", r.getNetwork),
|
||||
// POST
|
||||
local.NewPostRoute("/networks/create", r.postNetworkCreate),
|
||||
local.NewPostRoute("/networks/{id:.*}/connect", r.postNetworkConnect),
|
||||
local.NewPostRoute("/networks/{id:.*}/disconnect", r.postNetworkDisconnect),
|
||||
// DELETE
|
||||
local.NewDeleteRoute("/networks/{id:.*}", r.deleteNetwork),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
// +build experimental
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/libnetwork/api"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
var httpMethods = []string{"GET", "POST", "PUT", "DELETE"}
|
||||
|
||||
// NewRouter initializes a new network router
|
||||
func NewRouter(d *daemon.Daemon) router.Router {
|
||||
c := d.NetworkController()
|
||||
if c == nil {
|
||||
return networkRouter{}
|
||||
}
|
||||
|
||||
var routes []router.Route
|
||||
netHandler := api.NewHTTPHandler(c)
|
||||
|
||||
// TODO: libnetwork should stop hijacking request/response.
|
||||
// It should define API functions to add normally to the router.
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
netHandler(w, r)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, path := range []string{"/networks", "/services", "/sandboxes"} {
|
||||
routes = append(routes, networkRoute{path, handler})
|
||||
}
|
||||
|
||||
return networkRouter{routes}
|
||||
}
|
||||
|
||||
// Register adds the filtered handler to the mux.
|
||||
func (n networkRoute) Register(m *mux.Router, handler http.Handler) {
|
||||
logrus.Debugf("Registering %s, %v", n.path, httpMethods)
|
||||
subrouter := m.PathPrefix(router.VersionMatcher + n.path).Subrouter()
|
||||
subrouter.Methods(httpMethods...).Handler(handler)
|
||||
|
||||
subrouter = m.PathPrefix(n.path).Subrouter()
|
||||
subrouter.Methods(httpMethods...).Handler(handler)
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/docker/pkg/parsers/filters"
|
||||
"github.com/docker/libnetwork"
|
||||
)
|
||||
|
||||
func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filter := r.Form.Get("filters")
|
||||
netFilters, err := filters.FromParam(filter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
list := []*types.NetworkResource{}
|
||||
var nameFilter, idFilter bool
|
||||
var names, ids []string
|
||||
if names, nameFilter = netFilters["name"]; nameFilter {
|
||||
for _, name := range names {
|
||||
if nw, err := n.daemon.GetNetwork(name, daemon.NetworkByName); err == nil {
|
||||
list = append(list, buildNetworkResource(nw))
|
||||
} else {
|
||||
logrus.Errorf("failed to get network for filter=%s : %v", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ids, idFilter = netFilters["id"]; idFilter {
|
||||
for _, id := range ids {
|
||||
for _, nw := range n.daemon.GetNetworksByID(id) {
|
||||
list = append(list, buildNetworkResource(nw))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !nameFilter && !idFilter {
|
||||
nwList := n.daemon.GetNetworksByID("")
|
||||
for _, nw := range nwList {
|
||||
list = append(list, buildNetworkResource(nw))
|
||||
}
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, list)
|
||||
}
|
||||
|
||||
func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nw, err := n.daemon.FindNetwork(vars["id"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return httputils.WriteJSON(w, http.StatusOK, buildNetworkResource(nw))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&create); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nw, err := n.daemon.GetNetwork(create.Name, daemon.NetworkByName)
|
||||
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.daemon.CreateNetwork(create.Name, create.Driver, create.Options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return httputils.WriteJSON(w, http.StatusCreated, &types.NetworkCreateResponse{
|
||||
ID: nw.ID(),
|
||||
Warning: warning,
|
||||
})
|
||||
}
|
||||
|
||||
func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var connect types.NetworkConnect
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&connect); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nw, err := n.daemon.FindNetwork(vars["id"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
container, err := n.daemon.Get(connect.Container)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid container %s : %v", container, err)
|
||||
}
|
||||
return container.ConnectToNetwork(nw.Name())
|
||||
}
|
||||
|
||||
func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
var disconnect types.NetworkDisconnect
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&disconnect); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nw, err := n.daemon.FindNetwork(vars["id"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
container, err := n.daemon.Get(disconnect.Container)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid container %s : %v", container, err)
|
||||
}
|
||||
return container.DisconnectFromNetwork(nw)
|
||||
}
|
||||
|
||||
func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if err := httputils.ParseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nw, err := n.daemon.FindNetwork(vars["id"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nw.Delete()
|
||||
}
|
||||
|
||||
func buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
|
||||
r := &types.NetworkResource{}
|
||||
if nw == nil {
|
||||
return r
|
||||
}
|
||||
|
||||
r.Name = nw.Name()
|
||||
r.ID = nw.ID()
|
||||
r.Driver = nw.Type()
|
||||
r.Containers = make(map[string]types.EndpointResource)
|
||||
epl := nw.Endpoints()
|
||||
for _, e := range epl {
|
||||
sb := e.Info().Sandbox()
|
||||
if sb == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
r.Containers[sb.ContainerID()] = buildEndpointResource(e)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func buildEndpointResource(e libnetwork.Endpoint) types.EndpointResource {
|
||||
er := types.EndpointResource{}
|
||||
if e == nil {
|
||||
return er
|
||||
}
|
||||
|
||||
er.EndpointID = e.ID()
|
||||
if iface := e.Info().Iface(); iface != nil {
|
||||
if mac := iface.MacAddress(); mac != nil {
|
||||
er.MacAddress = mac.String()
|
||||
}
|
||||
if ip := iface.Address(); len(ip.IP) > 0 {
|
||||
er.IPv4Address = (&ip).String()
|
||||
}
|
||||
|
||||
if ipv6 := iface.AddressIPv6(); len(ipv6.IP) > 0 {
|
||||
er.IPv6Address = (&ipv6).String()
|
||||
}
|
||||
}
|
||||
return er
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// +build !experimental
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/router"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// NewRouter initializes a new network router
|
||||
func NewRouter(d *daemon.Daemon) router.Router {
|
||||
return networkRouter{}
|
||||
}
|
||||
|
||||
// Register adds the filtered handler to the mux.
|
||||
func (n networkRoute) Register(m *mux.Router, handler http.Handler) {
|
||||
}
|
||||
@@ -1,15 +1,6 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// VersionMatcher defines a variable matcher to be parsed by the router
|
||||
// when a request is about to be served.
|
||||
const VersionMatcher = "/v{version:[0-9.]+}"
|
||||
import "github.com/docker/docker/api/server/httputils"
|
||||
|
||||
// Router defines an interface to specify a group of routes to add the the docker server.
|
||||
type Router interface {
|
||||
@@ -18,8 +9,10 @@ type Router interface {
|
||||
|
||||
// Route defines an individual API route in the docker server.
|
||||
type Route interface {
|
||||
// Register adds the handler route to the docker mux.
|
||||
Register(*mux.Router, http.Handler)
|
||||
// Handler returns the raw function to create the http handler.
|
||||
Handler() httputils.APIFunc
|
||||
// Method returns the http method that the route responds to.
|
||||
Method() string
|
||||
// Path returns the subpath where the route responds to.
|
||||
Path() string
|
||||
}
|
||||
|
||||
+10
-3
@@ -19,6 +19,10 @@ import (
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// versionMatcher defines a variable matcher to be parsed by the router
|
||||
// when a request is about to be served.
|
||||
const versionMatcher = "/v{version:[0-9.]+}"
|
||||
|
||||
// Config provides the configuration for the API server
|
||||
type Config struct {
|
||||
Logging bool
|
||||
@@ -177,10 +181,13 @@ func (s *Server) CreateMux() *mux.Router {
|
||||
}
|
||||
|
||||
logrus.Debugf("Registering routers")
|
||||
for _, router := range s.routers {
|
||||
for _, r := range router.Routes() {
|
||||
for _, apiRouter := range s.routers {
|
||||
for _, r := range apiRouter.Routes() {
|
||||
f := s.makeHTTPHandler(r.Handler())
|
||||
r.Register(m, f)
|
||||
|
||||
logrus.Debugf("Registering %s, %s", r.Method(), r.Path())
|
||||
m.Path(versionMatcher + r.Path()).Methods(r.Method()).Handler(f)
|
||||
m.Path(r.Path()).Methods(r.Method()).Handler(f)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -308,3 +308,44 @@ type VolumeCreateRequest struct {
|
||||
Driver string // Driver is the name of the driver that should be used to create the volume
|
||||
DriverOpts map[string]string // DriverOpts holds the driver specific options to use for when creating the volume.
|
||||
}
|
||||
|
||||
// NetworkResource is the body of the "get network" http response message
|
||||
type NetworkResource struct {
|
||||
Name string `json:"name"`
|
||||
ID string `json:"id"`
|
||||
Driver string `json:"driver"`
|
||||
Containers map[string]EndpointResource `json:"containers"`
|
||||
Options map[string]interface{} `json:"options,omitempty"`
|
||||
}
|
||||
|
||||
//EndpointResource contains network resources allocated and usd for a container in a network
|
||||
type EndpointResource struct {
|
||||
EndpointID string `json:"endpoint"`
|
||||
MacAddress string `json:"mac_address"`
|
||||
IPv4Address string `json:"ipv4_address"`
|
||||
IPv6Address string `json:"ipv6_address"`
|
||||
}
|
||||
|
||||
// NetworkCreate is the expected body of the "create network" http request message
|
||||
type NetworkCreate struct {
|
||||
Name string `json:"name"`
|
||||
CheckDuplicate bool `json:"check_duplicate"`
|
||||
Driver string `json:"driver"`
|
||||
Options map[string]interface{} `json:"options"`
|
||||
}
|
||||
|
||||
// NetworkCreateResponse is the response message sent by the server for network create call
|
||||
type NetworkCreateResponse struct {
|
||||
ID string `json:"id"`
|
||||
Warning string `json:"warning"`
|
||||
}
|
||||
|
||||
// NetworkConnect represents the data to be used to connect a container to the network
|
||||
type NetworkConnect struct {
|
||||
Container string `json:"container"`
|
||||
}
|
||||
|
||||
// NetworkDisconnect represents the data to be used to disconnect a container from the network
|
||||
type NetworkDisconnect struct {
|
||||
Container string `json:"container"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user