* 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>
| ... | ... |
@@ -5,11 +5,9 @@ import ( |
| 5 | 5 |
|
| 6 | 6 |
"golang.org/x/net/context" |
| 7 | 7 |
|
| 8 |
- "github.com/Sirupsen/logrus" |
|
| 9 | 8 |
"github.com/docker/docker/api/server/httputils" |
| 10 | 9 |
dkrouter "github.com/docker/docker/api/server/router" |
| 11 | 10 |
"github.com/docker/docker/daemon" |
| 12 |
- "github.com/gorilla/mux" |
|
| 13 | 11 |
) |
| 14 | 12 |
|
| 15 | 13 |
// router is a docker router that talks with the local docker daemon. |
| ... | ... |
@@ -31,11 +29,14 @@ func (l localRoute) Handler() httputils.APIFunc {
|
| 31 | 31 |
return l.handler |
| 32 | 32 |
} |
| 33 | 33 |
|
| 34 |
-// Register adds the filtered handler to the mux. |
|
| 35 |
-func (l localRoute) Register(m *mux.Router, handler http.Handler) {
|
|
| 36 |
- logrus.Debugf("Registering %s, %s", l.method, l.path)
|
|
| 37 |
- m.Path(dkrouter.VersionMatcher + l.path).Methods(l.method).Handler(handler) |
|
| 38 |
- m.Path(l.path).Methods(l.method).Handler(handler) |
|
| 34 |
+// Method returns the http method that the route responds to. |
|
| 35 |
+func (l localRoute) Method() string {
|
|
| 36 |
+ return l.method |
|
| 37 |
+} |
|
| 38 |
+ |
|
| 39 |
+// Path returns the subpath where the route responds to. |
|
| 40 |
+func (l localRoute) Path() string {
|
|
| 41 |
+ return l.path |
|
| 39 | 42 |
} |
| 40 | 43 |
|
| 41 | 44 |
// NewRoute initialies a new local route for the reouter |
| ... | ... |
@@ -1,26 +1,41 @@ |
| 1 | 1 |
package network |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "github.com/docker/docker/api/server/httputils" |
|
| 5 | 4 |
"github.com/docker/docker/api/server/router" |
| 5 |
+ "github.com/docker/docker/api/server/router/local" |
|
| 6 |
+ "github.com/docker/docker/daemon" |
|
| 6 | 7 |
) |
| 7 | 8 |
|
| 8 | 9 |
// networkRouter is a router to talk with the network controller |
| 9 | 10 |
type networkRouter struct {
|
| 11 |
+ daemon *daemon.Daemon |
|
| 10 | 12 |
routes []router.Route |
| 11 | 13 |
} |
| 12 | 14 |
|
| 13 |
-// Routes returns the available routes to the network controller |
|
| 14 |
-func (n networkRouter) Routes() []router.Route {
|
|
| 15 |
- return n.routes |
|
| 15 |
+// NewRouter initializes a new network router |
|
| 16 |
+func NewRouter(d *daemon.Daemon) router.Router {
|
|
| 17 |
+ r := &networkRouter{
|
|
| 18 |
+ daemon: d, |
|
| 19 |
+ } |
|
| 20 |
+ r.initRoutes() |
|
| 21 |
+ return r |
|
| 16 | 22 |
} |
| 17 | 23 |
|
| 18 |
-type networkRoute struct {
|
|
| 19 |
- path string |
|
| 20 |
- handler httputils.APIFunc |
|
| 24 |
+// Routes returns the available routes to the network controller |
|
| 25 |
+func (r *networkRouter) Routes() []router.Route {
|
|
| 26 |
+ return r.routes |
|
| 21 | 27 |
} |
| 22 | 28 |
|
| 23 |
-// Handler returns the APIFunc to let the server wrap it in middlewares |
|
| 24 |
-func (l networkRoute) Handler() httputils.APIFunc {
|
|
| 25 |
- return l.handler |
|
| 29 |
+func (r *networkRouter) initRoutes() {
|
|
| 30 |
+ r.routes = []router.Route{
|
|
| 31 |
+ // GET |
|
| 32 |
+ local.NewGetRoute("/networks", r.getNetworksList),
|
|
| 33 |
+ local.NewGetRoute("/networks/{id:.*}", r.getNetwork),
|
|
| 34 |
+ // POST |
|
| 35 |
+ local.NewPostRoute("/networks/create", r.postNetworkCreate),
|
|
| 36 |
+ local.NewPostRoute("/networks/{id:.*}/connect", r.postNetworkConnect),
|
|
| 37 |
+ local.NewPostRoute("/networks/{id:.*}/disconnect", r.postNetworkDisconnect),
|
|
| 38 |
+ // DELETE |
|
| 39 |
+ local.NewDeleteRoute("/networks/{id:.*}", r.deleteNetwork),
|
|
| 40 |
+ } |
|
| 26 | 41 |
} |
| 27 | 42 |
deleted file mode 100644 |
| ... | ... |
@@ -1,51 +0,0 @@ |
| 1 |
-// +build experimental |
|
| 2 |
- |
|
| 3 |
-package network |
|
| 4 |
- |
|
| 5 |
-import ( |
|
| 6 |
- "net/http" |
|
| 7 |
- |
|
| 8 |
- "golang.org/x/net/context" |
|
| 9 |
- |
|
| 10 |
- "github.com/Sirupsen/logrus" |
|
| 11 |
- "github.com/docker/docker/api/server/router" |
|
| 12 |
- "github.com/docker/docker/daemon" |
|
| 13 |
- "github.com/docker/libnetwork/api" |
|
| 14 |
- "github.com/gorilla/mux" |
|
| 15 |
-) |
|
| 16 |
- |
|
| 17 |
-var httpMethods = []string{"GET", "POST", "PUT", "DELETE"}
|
|
| 18 |
- |
|
| 19 |
-// NewRouter initializes a new network router |
|
| 20 |
-func NewRouter(d *daemon.Daemon) router.Router {
|
|
| 21 |
- c := d.NetworkController() |
|
| 22 |
- if c == nil {
|
|
| 23 |
- return networkRouter{}
|
|
| 24 |
- } |
|
| 25 |
- |
|
| 26 |
- var routes []router.Route |
|
| 27 |
- netHandler := api.NewHTTPHandler(c) |
|
| 28 |
- |
|
| 29 |
- // TODO: libnetwork should stop hijacking request/response. |
|
| 30 |
- // It should define API functions to add normally to the router. |
|
| 31 |
- handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
|
| 32 |
- netHandler(w, r) |
|
| 33 |
- return nil |
|
| 34 |
- } |
|
| 35 |
- |
|
| 36 |
- for _, path := range []string{"/networks", "/services", "/sandboxes"} {
|
|
| 37 |
- routes = append(routes, networkRoute{path, handler})
|
|
| 38 |
- } |
|
| 39 |
- |
|
| 40 |
- return networkRouter{routes}
|
|
| 41 |
-} |
|
| 42 |
- |
|
| 43 |
-// Register adds the filtered handler to the mux. |
|
| 44 |
-func (n networkRoute) Register(m *mux.Router, handler http.Handler) {
|
|
| 45 |
- logrus.Debugf("Registering %s, %v", n.path, httpMethods)
|
|
| 46 |
- subrouter := m.PathPrefix(router.VersionMatcher + n.path).Subrouter() |
|
| 47 |
- subrouter.Methods(httpMethods...).Handler(handler) |
|
| 48 |
- |
|
| 49 |
- subrouter = m.PathPrefix(n.path).Subrouter() |
|
| 50 |
- subrouter.Methods(httpMethods...).Handler(handler) |
|
| 51 |
-} |
| 52 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,216 @@ |
| 0 |
+package network |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "encoding/json" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "net/http" |
|
| 6 |
+ |
|
| 7 |
+ "golang.org/x/net/context" |
|
| 8 |
+ |
|
| 9 |
+ "github.com/Sirupsen/logrus" |
|
| 10 |
+ "github.com/docker/docker/api/server/httputils" |
|
| 11 |
+ "github.com/docker/docker/api/types" |
|
| 12 |
+ "github.com/docker/docker/daemon" |
|
| 13 |
+ "github.com/docker/docker/pkg/parsers/filters" |
|
| 14 |
+ "github.com/docker/libnetwork" |
|
| 15 |
+) |
|
| 16 |
+ |
|
| 17 |
+func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
|
| 18 |
+ if err := httputils.ParseForm(r); err != nil {
|
|
| 19 |
+ return err |
|
| 20 |
+ } |
|
| 21 |
+ |
|
| 22 |
+ filter := r.Form.Get("filters")
|
|
| 23 |
+ netFilters, err := filters.FromParam(filter) |
|
| 24 |
+ if err != nil {
|
|
| 25 |
+ return err |
|
| 26 |
+ } |
|
| 27 |
+ |
|
| 28 |
+ list := []*types.NetworkResource{}
|
|
| 29 |
+ var nameFilter, idFilter bool |
|
| 30 |
+ var names, ids []string |
|
| 31 |
+ if names, nameFilter = netFilters["name"]; nameFilter {
|
|
| 32 |
+ for _, name := range names {
|
|
| 33 |
+ if nw, err := n.daemon.GetNetwork(name, daemon.NetworkByName); err == nil {
|
|
| 34 |
+ list = append(list, buildNetworkResource(nw)) |
|
| 35 |
+ } else {
|
|
| 36 |
+ logrus.Errorf("failed to get network for filter=%s : %v", name, err)
|
|
| 37 |
+ } |
|
| 38 |
+ } |
|
| 39 |
+ } |
|
| 40 |
+ |
|
| 41 |
+ if ids, idFilter = netFilters["id"]; idFilter {
|
|
| 42 |
+ for _, id := range ids {
|
|
| 43 |
+ for _, nw := range n.daemon.GetNetworksByID(id) {
|
|
| 44 |
+ list = append(list, buildNetworkResource(nw)) |
|
| 45 |
+ } |
|
| 46 |
+ } |
|
| 47 |
+ } |
|
| 48 |
+ |
|
| 49 |
+ if !nameFilter && !idFilter {
|
|
| 50 |
+ nwList := n.daemon.GetNetworksByID("")
|
|
| 51 |
+ for _, nw := range nwList {
|
|
| 52 |
+ list = append(list, buildNetworkResource(nw)) |
|
| 53 |
+ } |
|
| 54 |
+ } |
|
| 55 |
+ return httputils.WriteJSON(w, http.StatusOK, list) |
|
| 56 |
+} |
|
| 57 |
+ |
|
| 58 |
+func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
|
| 59 |
+ if err := httputils.ParseForm(r); err != nil {
|
|
| 60 |
+ return err |
|
| 61 |
+ } |
|
| 62 |
+ |
|
| 63 |
+ nw, err := n.daemon.FindNetwork(vars["id"]) |
|
| 64 |
+ if err != nil {
|
|
| 65 |
+ return err |
|
| 66 |
+ } |
|
| 67 |
+ return httputils.WriteJSON(w, http.StatusOK, buildNetworkResource(nw)) |
|
| 68 |
+} |
|
| 69 |
+ |
|
| 70 |
+func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
|
| 71 |
+ var create types.NetworkCreate |
|
| 72 |
+ var warning string |
|
| 73 |
+ |
|
| 74 |
+ if err := httputils.ParseForm(r); err != nil {
|
|
| 75 |
+ return err |
|
| 76 |
+ } |
|
| 77 |
+ |
|
| 78 |
+ if err := httputils.CheckForJSON(r); err != nil {
|
|
| 79 |
+ return err |
|
| 80 |
+ } |
|
| 81 |
+ |
|
| 82 |
+ if err := json.NewDecoder(r.Body).Decode(&create); err != nil {
|
|
| 83 |
+ return err |
|
| 84 |
+ } |
|
| 85 |
+ |
|
| 86 |
+ nw, err := n.daemon.GetNetwork(create.Name, daemon.NetworkByName) |
|
| 87 |
+ if _, ok := err.(libnetwork.ErrNoSuchNetwork); err != nil && !ok {
|
|
| 88 |
+ return err |
|
| 89 |
+ } |
|
| 90 |
+ if nw != nil {
|
|
| 91 |
+ if create.CheckDuplicate {
|
|
| 92 |
+ return libnetwork.NetworkNameError(create.Name) |
|
| 93 |
+ } |
|
| 94 |
+ warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID())
|
|
| 95 |
+ } |
|
| 96 |
+ |
|
| 97 |
+ nw, err = n.daemon.CreateNetwork(create.Name, create.Driver, create.Options) |
|
| 98 |
+ if err != nil {
|
|
| 99 |
+ return err |
|
| 100 |
+ } |
|
| 101 |
+ |
|
| 102 |
+ return httputils.WriteJSON(w, http.StatusCreated, &types.NetworkCreateResponse{
|
|
| 103 |
+ ID: nw.ID(), |
|
| 104 |
+ Warning: warning, |
|
| 105 |
+ }) |
|
| 106 |
+} |
|
| 107 |
+ |
|
| 108 |
+func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
|
| 109 |
+ var connect types.NetworkConnect |
|
| 110 |
+ if err := httputils.ParseForm(r); err != nil {
|
|
| 111 |
+ return err |
|
| 112 |
+ } |
|
| 113 |
+ |
|
| 114 |
+ if err := httputils.CheckForJSON(r); err != nil {
|
|
| 115 |
+ return err |
|
| 116 |
+ } |
|
| 117 |
+ |
|
| 118 |
+ if err := json.NewDecoder(r.Body).Decode(&connect); err != nil {
|
|
| 119 |
+ return err |
|
| 120 |
+ } |
|
| 121 |
+ |
|
| 122 |
+ nw, err := n.daemon.FindNetwork(vars["id"]) |
|
| 123 |
+ if err != nil {
|
|
| 124 |
+ return err |
|
| 125 |
+ } |
|
| 126 |
+ |
|
| 127 |
+ container, err := n.daemon.Get(connect.Container) |
|
| 128 |
+ if err != nil {
|
|
| 129 |
+ return fmt.Errorf("invalid container %s : %v", container, err)
|
|
| 130 |
+ } |
|
| 131 |
+ return container.ConnectToNetwork(nw.Name()) |
|
| 132 |
+} |
|
| 133 |
+ |
|
| 134 |
+func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
|
| 135 |
+ var disconnect types.NetworkDisconnect |
|
| 136 |
+ if err := httputils.ParseForm(r); err != nil {
|
|
| 137 |
+ return err |
|
| 138 |
+ } |
|
| 139 |
+ |
|
| 140 |
+ if err := httputils.CheckForJSON(r); err != nil {
|
|
| 141 |
+ return err |
|
| 142 |
+ } |
|
| 143 |
+ |
|
| 144 |
+ if err := json.NewDecoder(r.Body).Decode(&disconnect); err != nil {
|
|
| 145 |
+ return err |
|
| 146 |
+ } |
|
| 147 |
+ |
|
| 148 |
+ nw, err := n.daemon.FindNetwork(vars["id"]) |
|
| 149 |
+ if err != nil {
|
|
| 150 |
+ return err |
|
| 151 |
+ } |
|
| 152 |
+ |
|
| 153 |
+ container, err := n.daemon.Get(disconnect.Container) |
|
| 154 |
+ if err != nil {
|
|
| 155 |
+ return fmt.Errorf("invalid container %s : %v", container, err)
|
|
| 156 |
+ } |
|
| 157 |
+ return container.DisconnectFromNetwork(nw) |
|
| 158 |
+} |
|
| 159 |
+ |
|
| 160 |
+func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
|
| 161 |
+ if err := httputils.ParseForm(r); err != nil {
|
|
| 162 |
+ return err |
|
| 163 |
+ } |
|
| 164 |
+ |
|
| 165 |
+ nw, err := n.daemon.FindNetwork(vars["id"]) |
|
| 166 |
+ if err != nil {
|
|
| 167 |
+ return err |
|
| 168 |
+ } |
|
| 169 |
+ |
|
| 170 |
+ return nw.Delete() |
|
| 171 |
+} |
|
| 172 |
+ |
|
| 173 |
+func buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
|
|
| 174 |
+ r := &types.NetworkResource{}
|
|
| 175 |
+ if nw == nil {
|
|
| 176 |
+ return r |
|
| 177 |
+ } |
|
| 178 |
+ |
|
| 179 |
+ r.Name = nw.Name() |
|
| 180 |
+ r.ID = nw.ID() |
|
| 181 |
+ r.Driver = nw.Type() |
|
| 182 |
+ r.Containers = make(map[string]types.EndpointResource) |
|
| 183 |
+ epl := nw.Endpoints() |
|
| 184 |
+ for _, e := range epl {
|
|
| 185 |
+ sb := e.Info().Sandbox() |
|
| 186 |
+ if sb == nil {
|
|
| 187 |
+ continue |
|
| 188 |
+ } |
|
| 189 |
+ |
|
| 190 |
+ r.Containers[sb.ContainerID()] = buildEndpointResource(e) |
|
| 191 |
+ } |
|
| 192 |
+ return r |
|
| 193 |
+} |
|
| 194 |
+ |
|
| 195 |
+func buildEndpointResource(e libnetwork.Endpoint) types.EndpointResource {
|
|
| 196 |
+ er := types.EndpointResource{}
|
|
| 197 |
+ if e == nil {
|
|
| 198 |
+ return er |
|
| 199 |
+ } |
|
| 200 |
+ |
|
| 201 |
+ er.EndpointID = e.ID() |
|
| 202 |
+ if iface := e.Info().Iface(); iface != nil {
|
|
| 203 |
+ if mac := iface.MacAddress(); mac != nil {
|
|
| 204 |
+ er.MacAddress = mac.String() |
|
| 205 |
+ } |
|
| 206 |
+ if ip := iface.Address(); len(ip.IP) > 0 {
|
|
| 207 |
+ er.IPv4Address = (&ip).String() |
|
| 208 |
+ } |
|
| 209 |
+ |
|
| 210 |
+ if ipv6 := iface.AddressIPv6(); len(ipv6.IP) > 0 {
|
|
| 211 |
+ er.IPv6Address = (&ipv6).String() |
|
| 212 |
+ } |
|
| 213 |
+ } |
|
| 214 |
+ return er |
|
| 215 |
+} |
| 0 | 216 |
deleted file mode 100644 |
| ... | ... |
@@ -1,20 +0,0 @@ |
| 1 |
-// +build !experimental |
|
| 2 |
- |
|
| 3 |
-package network |
|
| 4 |
- |
|
| 5 |
-import ( |
|
| 6 |
- "net/http" |
|
| 7 |
- |
|
| 8 |
- "github.com/docker/docker/api/server/router" |
|
| 9 |
- "github.com/docker/docker/daemon" |
|
| 10 |
- "github.com/gorilla/mux" |
|
| 11 |
-) |
|
| 12 |
- |
|
| 13 |
-// NewRouter initializes a new network router |
|
| 14 |
-func NewRouter(d *daemon.Daemon) router.Router {
|
|
| 15 |
- return networkRouter{}
|
|
| 16 |
-} |
|
| 17 |
- |
|
| 18 |
-// Register adds the filtered handler to the mux. |
|
| 19 |
-func (n networkRoute) Register(m *mux.Router, handler http.Handler) {
|
|
| 20 |
-} |
| ... | ... |
@@ -1,15 +1,6 @@ |
| 1 | 1 |
package router |
| 2 | 2 |
|
| 3 |
-import ( |
|
| 4 |
- "net/http" |
|
| 5 |
- |
|
| 6 |
- "github.com/docker/docker/api/server/httputils" |
|
| 7 |
- "github.com/gorilla/mux" |
|
| 8 |
-) |
|
| 9 |
- |
|
| 10 |
-// VersionMatcher defines a variable matcher to be parsed by the router |
|
| 11 |
-// when a request is about to be served. |
|
| 12 |
-const VersionMatcher = "/v{version:[0-9.]+}"
|
|
| 3 |
+import "github.com/docker/docker/api/server/httputils" |
|
| 13 | 4 |
|
| 14 | 5 |
// Router defines an interface to specify a group of routes to add the the docker server. |
| 15 | 6 |
type Router interface {
|
| ... | ... |
@@ -18,8 +9,10 @@ type Router interface {
|
| 18 | 18 |
|
| 19 | 19 |
// Route defines an individual API route in the docker server. |
| 20 | 20 |
type Route interface {
|
| 21 |
- // Register adds the handler route to the docker mux. |
|
| 22 |
- Register(*mux.Router, http.Handler) |
|
| 23 | 21 |
// Handler returns the raw function to create the http handler. |
| 24 | 22 |
Handler() httputils.APIFunc |
| 23 |
+ // Method returns the http method that the route responds to. |
|
| 24 |
+ Method() string |
|
| 25 |
+ // Path returns the subpath where the route responds to. |
|
| 26 |
+ Path() string |
|
| 25 | 27 |
} |
| ... | ... |
@@ -19,6 +19,10 @@ import ( |
| 19 | 19 |
"golang.org/x/net/context" |
| 20 | 20 |
) |
| 21 | 21 |
|
| 22 |
+// versionMatcher defines a variable matcher to be parsed by the router |
|
| 23 |
+// when a request is about to be served. |
|
| 24 |
+const versionMatcher = "/v{version:[0-9.]+}"
|
|
| 25 |
+ |
|
| 22 | 26 |
// Config provides the configuration for the API server |
| 23 | 27 |
type Config struct {
|
| 24 | 28 |
Logging bool |
| ... | ... |
@@ -177,10 +181,13 @@ func (s *Server) CreateMux() *mux.Router {
|
| 177 | 177 |
} |
| 178 | 178 |
|
| 179 | 179 |
logrus.Debugf("Registering routers")
|
| 180 |
- for _, router := range s.routers {
|
|
| 181 |
- for _, r := range router.Routes() {
|
|
| 180 |
+ for _, apiRouter := range s.routers {
|
|
| 181 |
+ for _, r := range apiRouter.Routes() {
|
|
| 182 | 182 |
f := s.makeHTTPHandler(r.Handler()) |
| 183 |
- r.Register(m, f) |
|
| 183 |
+ |
|
| 184 |
+ logrus.Debugf("Registering %s, %s", r.Method(), r.Path())
|
|
| 185 |
+ m.Path(versionMatcher + r.Path()).Methods(r.Method()).Handler(f) |
|
| 186 |
+ m.Path(r.Path()).Methods(r.Method()).Handler(f) |
|
| 184 | 187 |
} |
| 185 | 188 |
} |
| 186 | 189 |
|
| ... | ... |
@@ -308,3 +308,44 @@ type VolumeCreateRequest struct {
|
| 308 | 308 |
Driver string // Driver is the name of the driver that should be used to create the volume |
| 309 | 309 |
DriverOpts map[string]string // DriverOpts holds the driver specific options to use for when creating the volume. |
| 310 | 310 |
} |
| 311 |
+ |
|
| 312 |
+// NetworkResource is the body of the "get network" http response message |
|
| 313 |
+type NetworkResource struct {
|
|
| 314 |
+ Name string `json:"name"` |
|
| 315 |
+ ID string `json:"id"` |
|
| 316 |
+ Driver string `json:"driver"` |
|
| 317 |
+ Containers map[string]EndpointResource `json:"containers"` |
|
| 318 |
+ Options map[string]interface{} `json:"options,omitempty"`
|
|
| 319 |
+} |
|
| 320 |
+ |
|
| 321 |
+//EndpointResource contains network resources allocated and usd for a container in a network |
|
| 322 |
+type EndpointResource struct {
|
|
| 323 |
+ EndpointID string `json:"endpoint"` |
|
| 324 |
+ MacAddress string `json:"mac_address"` |
|
| 325 |
+ IPv4Address string `json:"ipv4_address"` |
|
| 326 |
+ IPv6Address string `json:"ipv6_address"` |
|
| 327 |
+} |
|
| 328 |
+ |
|
| 329 |
+// NetworkCreate is the expected body of the "create network" http request message |
|
| 330 |
+type NetworkCreate struct {
|
|
| 331 |
+ Name string `json:"name"` |
|
| 332 |
+ CheckDuplicate bool `json:"check_duplicate"` |
|
| 333 |
+ Driver string `json:"driver"` |
|
| 334 |
+ Options map[string]interface{} `json:"options"`
|
|
| 335 |
+} |
|
| 336 |
+ |
|
| 337 |
+// NetworkCreateResponse is the response message sent by the server for network create call |
|
| 338 |
+type NetworkCreateResponse struct {
|
|
| 339 |
+ ID string `json:"id"` |
|
| 340 |
+ Warning string `json:"warning"` |
|
| 341 |
+} |
|
| 342 |
+ |
|
| 343 |
+// NetworkConnect represents the data to be used to connect a container to the network |
|
| 344 |
+type NetworkConnect struct {
|
|
| 345 |
+ Container string `json:"container"` |
|
| 346 |
+} |
|
| 347 |
+ |
|
| 348 |
+// NetworkDisconnect represents the data to be used to disconnect a container from the network |
|
| 349 |
+type NetworkDisconnect struct {
|
|
| 350 |
+ Container string `json:"container"` |
|
| 351 |
+} |
| 311 | 352 |
deleted file mode 100644 |
| ... | ... |
@@ -1,9 +0,0 @@ |
| 1 |
-// +build experimental |
|
| 2 |
- |
|
| 3 |
-package daemon |
|
| 4 |
- |
|
| 5 |
-import flag "github.com/docker/docker/pkg/mflag" |
|
| 6 |
- |
|
| 7 |
-func (config *Config) attachExperimentalFlags(cmd *flag.FlagSet, usageFn func(string) string) {
|
|
| 8 |
- cmd.StringVar(&config.DefaultNetwork, []string{"-default-network"}, "", usageFn("Set default network"))
|
|
| 9 |
-} |
| ... | ... |
@@ -77,6 +77,4 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin |
| 77 | 77 |
cmd.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, usageFn("Use userland proxy for loopback traffic"))
|
| 78 | 78 |
cmd.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, usageFn("Enable CORS headers in the remote API, this is deprecated by --api-cors-header"))
|
| 79 | 79 |
cmd.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", usageFn("Set CORS headers in the remote API"))
|
| 80 |
- |
|
| 81 |
- config.attachExperimentalFlags(cmd, usageFn) |
|
| 82 | 80 |
} |
| ... | ... |
@@ -412,7 +412,7 @@ func (container *Container) buildHostnameFile() error {
|
| 412 | 412 |
return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) |
| 413 | 413 |
} |
| 414 | 414 |
|
| 415 |
-func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, error) {
|
|
| 415 |
+func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetwork.SandboxOption, error) {
|
|
| 416 | 416 |
var ( |
| 417 | 417 |
sboxOptions []libnetwork.SandboxOption |
| 418 | 418 |
err error |
| ... | ... |
@@ -487,6 +487,23 @@ func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, e |
| 487 | 487 |
} |
| 488 | 488 |
} |
| 489 | 489 |
|
| 490 |
+ for _, extraHost := range container.hostConfig.ExtraHosts {
|
|
| 491 |
+ // allow IPv6 addresses in extra hosts; only split on first ":" |
|
| 492 |
+ parts := strings.SplitN(extraHost, ":", 2) |
|
| 493 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1])) |
|
| 494 |
+ } |
|
| 495 |
+ |
|
| 496 |
+ // Link feature is supported only for the default bridge network. |
|
| 497 |
+ // return if this call to build join options is not for default bridge network |
|
| 498 |
+ if n.Name() != "bridge" {
|
|
| 499 |
+ return sboxOptions, nil |
|
| 500 |
+ } |
|
| 501 |
+ |
|
| 502 |
+ ep, _ := container.getEndpointInNetwork(n) |
|
| 503 |
+ if ep == nil {
|
|
| 504 |
+ return sboxOptions, nil |
|
| 505 |
+ } |
|
| 506 |
+ |
|
| 490 | 507 |
var childEndpoints, parentEndpoints []string |
| 491 | 508 |
|
| 492 | 509 |
children, err := container.daemon.children(container.Name) |
| ... | ... |
@@ -503,17 +520,12 @@ func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, e |
| 503 | 503 |
aliasList = aliasList + " " + child.Name[1:] |
| 504 | 504 |
} |
| 505 | 505 |
sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.IPAddress)) |
| 506 |
- if child.NetworkSettings.EndpointID != "" {
|
|
| 507 |
- childEndpoints = append(childEndpoints, child.NetworkSettings.EndpointID) |
|
| 506 |
+ cEndpoint, _ := child.getEndpointInNetwork(n) |
|
| 507 |
+ if cEndpoint != nil && cEndpoint.ID() != "" {
|
|
| 508 |
+ childEndpoints = append(childEndpoints, cEndpoint.ID()) |
|
| 508 | 509 |
} |
| 509 | 510 |
} |
| 510 | 511 |
|
| 511 |
- for _, extraHost := range container.hostConfig.ExtraHosts {
|
|
| 512 |
- // allow IPv6 addresses in extra hosts; only split on first ":" |
|
| 513 |
- parts := strings.SplitN(extraHost, ":", 2) |
|
| 514 |
- sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1])) |
|
| 515 |
- } |
|
| 516 |
- |
|
| 517 | 512 |
refs := container.daemon.containerGraph().RefPaths(container.ID) |
| 518 | 513 |
for _, ref := range refs {
|
| 519 | 514 |
if ref.ParentID == "0" {
|
| ... | ... |
@@ -528,8 +540,8 @@ func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, e |
| 528 | 528 |
if c != nil && !container.daemon.configStore.DisableBridge && container.hostConfig.NetworkMode.IsPrivate() {
|
| 529 | 529 |
logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress)
|
| 530 | 530 |
sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, container.NetworkSettings.IPAddress)) |
| 531 |
- if c.NetworkSettings.EndpointID != "" {
|
|
| 532 |
- parentEndpoints = append(parentEndpoints, c.NetworkSettings.EndpointID) |
|
| 531 |
+ if ep.ID() != "" {
|
|
| 532 |
+ parentEndpoints = append(parentEndpoints, ep.ID()) |
|
| 533 | 533 |
} |
| 534 | 534 |
} |
| 535 | 535 |
} |
| ... | ... |
@@ -546,6 +558,11 @@ func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, e |
| 546 | 546 |
return sboxOptions, nil |
| 547 | 547 |
} |
| 548 | 548 |
|
| 549 |
+func (container *Container) getEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
|
|
| 550 |
+ endpointName := strings.TrimPrefix(container.Name, "/") |
|
| 551 |
+ return n.EndpointByName(endpointName) |
|
| 552 |
+} |
|
| 553 |
+ |
|
| 549 | 554 |
func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
|
| 550 | 555 |
if ep == nil {
|
| 551 | 556 |
return nil, derr.ErrorCodeEmptyEndpoint |
| ... | ... |
@@ -650,10 +667,38 @@ func (container *Container) updateJoinInfo(ep libnetwork.Endpoint) error {
|
| 650 | 650 |
return nil |
| 651 | 651 |
} |
| 652 | 652 |
|
| 653 |
-func (container *Container) updateEndpointNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error {
|
|
| 654 |
- networkSettings := &network.Settings{NetworkID: n.ID(), EndpointID: ep.ID()}
|
|
| 653 |
+func (container *Container) updateNetworkSettings(n libnetwork.Network) error {
|
|
| 654 |
+ if container.NetworkSettings == nil {
|
|
| 655 |
+ container.NetworkSettings = &network.Settings{Networks: []string{}}
|
|
| 656 |
+ } |
|
| 657 |
+ settings := container.NetworkSettings |
|
| 658 |
+ |
|
| 659 |
+ for _, s := range settings.Networks {
|
|
| 660 |
+ sn, err := container.daemon.FindNetwork(s) |
|
| 661 |
+ if err != nil {
|
|
| 662 |
+ continue |
|
| 663 |
+ } |
|
| 664 |
+ |
|
| 665 |
+ if sn.Name() == n.Name() {
|
|
| 666 |
+ // Avoid duplicate config |
|
| 667 |
+ return nil |
|
| 668 |
+ } |
|
| 669 |
+ if !runconfig.NetworkMode(sn.Type()).IsPrivate() || |
|
| 670 |
+ !runconfig.NetworkMode(n.Type()).IsPrivate() {
|
|
| 671 |
+ return runconfig.ErrConflictSharedNetwork |
|
| 672 |
+ } |
|
| 673 |
+ if runconfig.NetworkMode(sn.Name()).IsNone() || |
|
| 674 |
+ runconfig.NetworkMode(n.Name()).IsNone() {
|
|
| 675 |
+ return runconfig.ErrConflictNoNetwork |
|
| 676 |
+ } |
|
| 677 |
+ } |
|
| 678 |
+ settings.Networks = append(settings.Networks, n.Name()) |
|
| 655 | 679 |
|
| 656 |
- networkSettings, err := container.buildPortMapInfo(ep, networkSettings) |
|
| 680 |
+ return nil |
|
| 681 |
+} |
|
| 682 |
+ |
|
| 683 |
+func (container *Container) updateEndpointNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error {
|
|
| 684 |
+ networkSettings, err := container.buildPortMapInfo(ep, container.NetworkSettings) |
|
| 657 | 685 |
if err != nil {
|
| 658 | 686 |
return err |
| 659 | 687 |
} |
| ... | ... |
@@ -667,7 +712,6 @@ func (container *Container) updateEndpointNetworkSettings(n libnetwork.Network, |
| 667 | 667 |
networkSettings.Bridge = container.daemon.configStore.Bridge.Iface |
| 668 | 668 |
} |
| 669 | 669 |
|
| 670 |
- container.NetworkSettings = networkSettings |
|
| 671 | 670 |
return nil |
| 672 | 671 |
} |
| 673 | 672 |
|
| ... | ... |
@@ -688,7 +732,25 @@ func (container *Container) updateNetwork() error {
|
| 688 | 688 |
return derr.ErrorCodeNoSandbox.WithArgs(sid, err) |
| 689 | 689 |
} |
| 690 | 690 |
|
| 691 |
- options, err := container.buildSandboxOptions() |
|
| 691 |
+ // Find if container is connected to the default bridge network |
|
| 692 |
+ var n libnetwork.Network |
|
| 693 |
+ for _, name := range container.NetworkSettings.Networks {
|
|
| 694 |
+ sn, err := container.daemon.FindNetwork(name) |
|
| 695 |
+ if err != nil {
|
|
| 696 |
+ continue |
|
| 697 |
+ } |
|
| 698 |
+ if sn.Name() == "bridge" {
|
|
| 699 |
+ n = sn |
|
| 700 |
+ break |
|
| 701 |
+ } |
|
| 702 |
+ } |
|
| 703 |
+ |
|
| 704 |
+ if n == nil {
|
|
| 705 |
+ // Not connected to the default bridge network; Nothing to do |
|
| 706 |
+ return nil |
|
| 707 |
+ } |
|
| 708 |
+ |
|
| 709 |
+ options, err := container.buildSandboxOptions(n) |
|
| 692 | 710 |
if err != nil {
|
| 693 | 711 |
return derr.ErrorCodeNetworkUpdate.WithArgs(err) |
| 694 | 712 |
} |
| ... | ... |
@@ -781,20 +843,6 @@ func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointO |
| 781 | 781 |
return createOptions, nil |
| 782 | 782 |
} |
| 783 | 783 |
|
| 784 |
-func parseService(controller libnetwork.NetworkController, service string) (string, string, string) {
|
|
| 785 |
- dn := controller.Config().Daemon.DefaultNetwork |
|
| 786 |
- dd := controller.Config().Daemon.DefaultDriver |
|
| 787 |
- |
|
| 788 |
- snd := strings.Split(service, ".") |
|
| 789 |
- if len(snd) > 2 {
|
|
| 790 |
- return strings.Join(snd[:len(snd)-2], "."), snd[len(snd)-2], snd[len(snd)-1] |
|
| 791 |
- } |
|
| 792 |
- if len(snd) > 1 {
|
|
| 793 |
- return snd[0], snd[1], dd |
|
| 794 |
- } |
|
| 795 |
- return snd[0], dn, dd |
|
| 796 |
-} |
|
| 797 |
- |
|
| 798 | 784 |
func createNetwork(controller libnetwork.NetworkController, dnet string, driver string) (libnetwork.Network, error) {
|
| 799 | 785 |
createOptions := []libnetwork.NetworkOption{}
|
| 800 | 786 |
genericOption := options.Generic{}
|
| ... | ... |
@@ -813,61 +861,69 @@ func createNetwork(controller libnetwork.NetworkController, dnet string, driver |
| 813 | 813 |
} |
| 814 | 814 |
|
| 815 | 815 |
func (container *Container) allocateNetwork() error {
|
| 816 |
- mode := container.hostConfig.NetworkMode |
|
| 817 |
- controller := container.daemon.netController |
|
| 818 |
- if container.Config.NetworkDisabled || mode.IsContainer() {
|
|
| 819 |
- return nil |
|
| 820 |
- } |
|
| 816 |
+ settings := container.NetworkSettings.Networks |
|
| 817 |
+ updateSettings := false |
|
| 818 |
+ if settings == nil {
|
|
| 819 |
+ mode := container.hostConfig.NetworkMode |
|
| 820 |
+ controller := container.daemon.netController |
|
| 821 |
+ if container.Config.NetworkDisabled || mode.IsContainer() {
|
|
| 822 |
+ return nil |
|
| 823 |
+ } |
|
| 821 | 824 |
|
| 822 |
- networkDriver := string(mode) |
|
| 823 |
- service := container.Config.PublishService |
|
| 824 |
- networkName := mode.NetworkName() |
|
| 825 |
- if mode.IsDefault() {
|
|
| 826 |
- if service != "" {
|
|
| 827 |
- service, networkName, networkDriver = parseService(controller, service) |
|
| 828 |
- } else {
|
|
| 825 |
+ networkName := mode.NetworkName() |
|
| 826 |
+ if mode.IsDefault() {
|
|
| 829 | 827 |
networkName = controller.Config().Daemon.DefaultNetwork |
| 830 |
- networkDriver = controller.Config().Daemon.DefaultDriver |
|
| 831 | 828 |
} |
| 832 |
- } else if service != "" {
|
|
| 833 |
- return derr.ErrorCodeNetworkConflict |
|
| 829 |
+ settings = []string{networkName}
|
|
| 830 |
+ updateSettings = true |
|
| 834 | 831 |
} |
| 835 | 832 |
|
| 836 |
- if runconfig.NetworkMode(networkDriver).IsBridge() && container.daemon.configStore.DisableBridge {
|
|
| 837 |
- container.Config.NetworkDisabled = true |
|
| 838 |
- return nil |
|
| 833 |
+ for _, n := range settings {
|
|
| 834 |
+ if err := container.connectToNetwork(n, updateSettings); err != nil {
|
|
| 835 |
+ if updateSettings {
|
|
| 836 |
+ return err |
|
| 837 |
+ } |
|
| 838 |
+ // dont fail a container restart case if the user removed the network |
|
| 839 |
+ logrus.Warnf("Could not connect container %s : %v", container.ID, err)
|
|
| 840 |
+ } |
|
| 839 | 841 |
} |
| 840 | 842 |
|
| 841 |
- if service == "" {
|
|
| 842 |
- // dot character "." has a special meaning to support SERVICE[.NETWORK] format. |
|
| 843 |
- // For backward compatibility, replacing "." with "-", instead of failing |
|
| 844 |
- service = strings.Replace(container.Name, ".", "-", -1) |
|
| 845 |
- // Service names dont like "/" in them. removing it instead of failing for backward compatibility |
|
| 846 |
- service = strings.Replace(service, "/", "", -1) |
|
| 843 |
+ return container.writeHostConfig() |
|
| 844 |
+} |
|
| 845 |
+ |
|
| 846 |
+// ConnectToNetwork connects a container to a netork |
|
| 847 |
+func (container *Container) ConnectToNetwork(idOrName string) error {
|
|
| 848 |
+ if !container.Running {
|
|
| 849 |
+ return derr.ErrorCodeNotRunning.WithArgs(container.ID) |
|
| 847 | 850 |
} |
| 851 |
+ return container.connectToNetwork(idOrName, true) |
|
| 852 |
+} |
|
| 848 | 853 |
|
| 849 |
- if err := container.configureNetwork(networkName, service, networkDriver, mode.IsDefault()); err != nil {
|
|
| 850 |
- return err |
|
| 854 |
+func (container *Container) connectToNetwork(idOrName string, updateSettings bool) error {
|
|
| 855 |
+ if container.hostConfig.NetworkMode.IsContainer() {
|
|
| 856 |
+ return runconfig.ErrConflictSharedNetwork |
|
| 851 | 857 |
} |
| 852 | 858 |
|
| 853 |
- return container.writeHostConfig() |
|
| 854 |
-} |
|
| 859 |
+ if runconfig.NetworkMode(idOrName).IsBridge() && |
|
| 860 |
+ container.daemon.configStore.DisableBridge {
|
|
| 861 |
+ container.Config.NetworkDisabled = true |
|
| 862 |
+ return nil |
|
| 863 |
+ } |
|
| 855 | 864 |
|
| 856 |
-func (container *Container) configureNetwork(networkName, service, networkDriver string, canCreateNetwork bool) error {
|
|
| 857 | 865 |
controller := container.daemon.netController |
| 858 | 866 |
|
| 859 |
- n, err := controller.NetworkByName(networkName) |
|
| 867 |
+ n, err := container.daemon.FindNetwork(idOrName) |
|
| 860 | 868 |
if err != nil {
|
| 861 |
- if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok || !canCreateNetwork {
|
|
| 862 |
- return err |
|
| 863 |
- } |
|
| 869 |
+ return err |
|
| 870 |
+ } |
|
| 864 | 871 |
|
| 865 |
- if n, err = createNetwork(controller, networkName, networkDriver); err != nil {
|
|
| 872 |
+ if updateSettings {
|
|
| 873 |
+ if err := container.updateNetworkSettings(n); err != nil {
|
|
| 866 | 874 |
return err |
| 867 | 875 |
} |
| 868 | 876 |
} |
| 869 | 877 |
|
| 870 |
- ep, err := n.EndpointByName(service) |
|
| 878 |
+ ep, err := container.getEndpointInNetwork(n) |
|
| 871 | 879 |
if err != nil {
|
| 872 | 880 |
if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok {
|
| 873 | 881 |
return err |
| ... | ... |
@@ -878,7 +934,8 @@ func (container *Container) configureNetwork(networkName, service, networkDriver |
| 878 | 878 |
return err |
| 879 | 879 |
} |
| 880 | 880 |
|
| 881 |
- ep, err = n.CreateEndpoint(service, createOptions...) |
|
| 881 |
+ endpointName := strings.TrimPrefix(container.Name, "/") |
|
| 882 |
+ ep, err = n.CreateEndpoint(endpointName, createOptions...) |
|
| 882 | 883 |
if err != nil {
|
| 883 | 884 |
return err |
| 884 | 885 |
} |
| ... | ... |
@@ -897,7 +954,7 @@ func (container *Container) configureNetwork(networkName, service, networkDriver |
| 897 | 897 |
return false |
| 898 | 898 |
}) |
| 899 | 899 |
if sb == nil {
|
| 900 |
- options, err := container.buildSandboxOptions() |
|
| 900 |
+ options, err := container.buildSandboxOptions(n) |
|
| 901 | 901 |
if err != nil {
|
| 902 | 902 |
return err |
| 903 | 903 |
} |
| ... | ... |
@@ -1039,12 +1096,11 @@ func (container *Container) releaseNetwork() {
|
| 1039 | 1039 |
} |
| 1040 | 1040 |
|
| 1041 | 1041 |
sid := container.NetworkSettings.SandboxID |
| 1042 |
- eid := container.NetworkSettings.EndpointID |
|
| 1043 |
- nid := container.NetworkSettings.NetworkID |
|
| 1042 |
+ networks := container.NetworkSettings.Networks |
|
| 1044 | 1043 |
|
| 1045 |
- container.NetworkSettings = &network.Settings{}
|
|
| 1044 |
+ container.NetworkSettings = &network.Settings{Networks: networks}
|
|
| 1046 | 1045 |
|
| 1047 |
- if sid == "" || nid == "" || eid == "" {
|
|
| 1046 |
+ if sid == "" || len(networks) == 0 {
|
|
| 1048 | 1047 |
return |
| 1049 | 1048 |
} |
| 1050 | 1049 |
|
| ... | ... |
@@ -1054,29 +1110,73 @@ func (container *Container) releaseNetwork() {
|
| 1054 | 1054 |
return |
| 1055 | 1055 |
} |
| 1056 | 1056 |
|
| 1057 |
- n, err := container.daemon.netController.NetworkByID(nid) |
|
| 1058 |
- if err != nil {
|
|
| 1059 |
- logrus.Errorf("error locating network id %s: %v", nid, err)
|
|
| 1060 |
- return |
|
| 1061 |
- } |
|
| 1062 |
- |
|
| 1063 |
- ep, err := n.EndpointByID(eid) |
|
| 1064 |
- if err != nil {
|
|
| 1065 |
- logrus.Errorf("error locating endpoint id %s: %v", eid, err)
|
|
| 1066 |
- return |
|
| 1057 |
+ for _, ns := range networks {
|
|
| 1058 |
+ n, err := container.daemon.FindNetwork(ns) |
|
| 1059 |
+ if err != nil {
|
|
| 1060 |
+ continue |
|
| 1061 |
+ } |
|
| 1062 |
+ container.disconnectFromNetwork(n, false) |
|
| 1067 | 1063 |
} |
| 1068 | 1064 |
|
| 1069 | 1065 |
if err := sb.Delete(); err != nil {
|
| 1070 | 1066 |
logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
|
| 1071 |
- return |
|
| 1067 |
+ } |
|
| 1068 |
+} |
|
| 1069 |
+ |
|
| 1070 |
+// DisconnectFromNetwork disconnects a container from a network |
|
| 1071 |
+func (container *Container) DisconnectFromNetwork(n libnetwork.Network) error {
|
|
| 1072 |
+ if !container.Running {
|
|
| 1073 |
+ return derr.ErrorCodeNotRunning.WithArgs(container.ID) |
|
| 1074 |
+ } |
|
| 1075 |
+ |
|
| 1076 |
+ return container.disconnectFromNetwork(n, true) |
|
| 1077 |
+} |
|
| 1078 |
+ |
|
| 1079 |
+func (container *Container) disconnectFromNetwork(n libnetwork.Network, updateSettings bool) error {
|
|
| 1080 |
+ var ( |
|
| 1081 |
+ ep libnetwork.Endpoint |
|
| 1082 |
+ sbox libnetwork.Sandbox |
|
| 1083 |
+ ) |
|
| 1084 |
+ |
|
| 1085 |
+ s := func(current libnetwork.Endpoint) bool {
|
|
| 1086 |
+ if sb := current.Info().Sandbox(); sb != nil {
|
|
| 1087 |
+ if sb.ContainerID() == container.ID {
|
|
| 1088 |
+ ep = current |
|
| 1089 |
+ sbox = sb |
|
| 1090 |
+ return true |
|
| 1091 |
+ } |
|
| 1092 |
+ } |
|
| 1093 |
+ return false |
|
| 1094 |
+ } |
|
| 1095 |
+ n.WalkEndpoints(s) |
|
| 1096 |
+ |
|
| 1097 |
+ if ep == nil {
|
|
| 1098 |
+ return fmt.Errorf("could not locate network endpoint for container %s", container.ID)
|
|
| 1099 |
+ } |
|
| 1100 |
+ |
|
| 1101 |
+ if err := ep.Leave(sbox); err != nil {
|
|
| 1102 |
+ return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err)
|
|
| 1072 | 1103 |
} |
| 1073 | 1104 |
|
| 1074 |
- // In addition to leaving all endpoints, delete implicitly created endpoint |
|
| 1075 |
- if container.Config.PublishService == "" {
|
|
| 1076 |
- if err := ep.Delete(); err != nil {
|
|
| 1077 |
- logrus.Errorf("deleting endpoint failed: %v", err)
|
|
| 1105 |
+ if err := ep.Delete(); err != nil {
|
|
| 1106 |
+ return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err)
|
|
| 1107 |
+ } |
|
| 1108 |
+ |
|
| 1109 |
+ if updateSettings {
|
|
| 1110 |
+ networks := container.NetworkSettings.Networks |
|
| 1111 |
+ for i, s := range networks {
|
|
| 1112 |
+ sn, err := container.daemon.FindNetwork(s) |
|
| 1113 |
+ if err != nil {
|
|
| 1114 |
+ continue |
|
| 1115 |
+ } |
|
| 1116 |
+ if sn.Name() == n.Name() {
|
|
| 1117 |
+ networks = append(networks[:i], networks[i+1:]...) |
|
| 1118 |
+ container.NetworkSettings.Networks = networks |
|
| 1119 |
+ break |
|
| 1120 |
+ } |
|
| 1078 | 1121 |
} |
| 1079 | 1122 |
} |
| 1123 |
+ return nil |
|
| 1080 | 1124 |
} |
| 1081 | 1125 |
|
| 1082 | 1126 |
func (container *Container) unmountVolumes(forceSyscall bool) error {
|
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
|
| 8 | 8 |
"github.com/docker/docker/daemon/execdriver" |
| 9 | 9 |
derr "github.com/docker/docker/errors" |
| 10 |
+ "github.com/docker/libnetwork" |
|
| 10 | 11 |
) |
| 11 | 12 |
|
| 12 | 13 |
// DefaultPathEnv is deliberately empty on Windows as the default path will be set by |
| ... | ... |
@@ -38,6 +39,16 @@ func (container *Container) initializeNetworking() error {
|
| 38 | 38 |
return nil |
| 39 | 39 |
} |
| 40 | 40 |
|
| 41 |
+// ConnectToNetwork connects a container to the network |
|
| 42 |
+func (container *Container) ConnectToNetwork(idOrName string) error {
|
|
| 43 |
+ return nil |
|
| 44 |
+} |
|
| 45 |
+ |
|
| 46 |
+// DisconnectFromNetwork disconnects a container from, the network |
|
| 47 |
+func (container *Container) DisconnectFromNetwork(n libnetwork.Network) error {
|
|
| 48 |
+ return nil |
|
| 49 |
+} |
|
| 50 |
+ |
|
| 41 | 51 |
func (container *Container) setupWorkingDirectory() error {
|
| 42 | 52 |
return nil |
| 43 | 53 |
} |
| ... | ... |
@@ -1162,11 +1162,6 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *runconfig.HostConfig, |
| 1162 | 1162 |
return verifyPlatformContainerSettings(daemon, hostConfig, config) |
| 1163 | 1163 |
} |
| 1164 | 1164 |
|
| 1165 |
-// NetworkController exposes the libnetwork interface to manage networks. |
|
| 1166 |
-func (daemon *Daemon) NetworkController() libnetwork.NetworkController {
|
|
| 1167 |
- return daemon.netController |
|
| 1168 |
-} |
|
| 1169 |
- |
|
| 1170 | 1165 |
func configureVolumes(config *Config) (*store.VolumeStore, error) {
|
| 1171 | 1166 |
volumesDriver, err := local.New(config.Root) |
| 1172 | 1167 |
if err != nil {
|
| 1173 | 1168 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,106 @@ |
| 0 |
+package daemon |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "errors" |
|
| 4 |
+ "strings" |
|
| 5 |
+ |
|
| 6 |
+ "github.com/docker/libnetwork" |
|
| 7 |
+ "github.com/docker/libnetwork/netlabel" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+const ( |
|
| 11 |
+ // NetworkByID represents a constant to find a network by its ID |
|
| 12 |
+ NetworkByID = iota + 1 |
|
| 13 |
+ // NetworkByName represents a constant to find a network by its Name |
|
| 14 |
+ NetworkByName |
|
| 15 |
+) |
|
| 16 |
+ |
|
| 17 |
+// FindNetwork function finds a network for a given string that can represent network name or id |
|
| 18 |
+func (daemon *Daemon) FindNetwork(idName string) (libnetwork.Network, error) {
|
|
| 19 |
+ // Find by Name |
|
| 20 |
+ n, err := daemon.GetNetwork(idName, NetworkByName) |
|
| 21 |
+ if _, ok := err.(libnetwork.ErrNoSuchNetwork); err != nil && !ok {
|
|
| 22 |
+ return nil, err |
|
| 23 |
+ } |
|
| 24 |
+ |
|
| 25 |
+ if n != nil {
|
|
| 26 |
+ return n, nil |
|
| 27 |
+ } |
|
| 28 |
+ |
|
| 29 |
+ // Find by id |
|
| 30 |
+ n, err = daemon.GetNetwork(idName, NetworkByID) |
|
| 31 |
+ if err != nil {
|
|
| 32 |
+ return nil, err |
|
| 33 |
+ } |
|
| 34 |
+ |
|
| 35 |
+ return n, nil |
|
| 36 |
+} |
|
| 37 |
+ |
|
| 38 |
+// GetNetwork function returns a network for a given string that represents the network and |
|
| 39 |
+// a hint to indicate if the string is an Id or Name of the network |
|
| 40 |
+func (daemon *Daemon) GetNetwork(idName string, by int) (libnetwork.Network, error) {
|
|
| 41 |
+ c := daemon.netController |
|
| 42 |
+ switch by {
|
|
| 43 |
+ case NetworkByID: |
|
| 44 |
+ list := daemon.GetNetworksByID(idName) |
|
| 45 |
+ |
|
| 46 |
+ if len(list) == 0 {
|
|
| 47 |
+ return nil, libnetwork.ErrNoSuchNetwork(idName) |
|
| 48 |
+ } |
|
| 49 |
+ |
|
| 50 |
+ if len(list) > 1 {
|
|
| 51 |
+ return nil, libnetwork.ErrInvalidID(idName) |
|
| 52 |
+ } |
|
| 53 |
+ |
|
| 54 |
+ return list[0], nil |
|
| 55 |
+ case NetworkByName: |
|
| 56 |
+ if idName == "" {
|
|
| 57 |
+ idName = c.Config().Daemon.DefaultNetwork |
|
| 58 |
+ } |
|
| 59 |
+ return c.NetworkByName(idName) |
|
| 60 |
+ } |
|
| 61 |
+ return nil, errors.New("unexpected selector for GetNetwork")
|
|
| 62 |
+} |
|
| 63 |
+ |
|
| 64 |
+// GetNetworksByID returns a list of networks whose ID partially matches zero or more networks |
|
| 65 |
+func (daemon *Daemon) GetNetworksByID(partialID string) []libnetwork.Network {
|
|
| 66 |
+ c := daemon.netController |
|
| 67 |
+ list := []libnetwork.Network{}
|
|
| 68 |
+ l := func(nw libnetwork.Network) bool {
|
|
| 69 |
+ if strings.HasPrefix(nw.ID(), partialID) {
|
|
| 70 |
+ list = append(list, nw) |
|
| 71 |
+ } |
|
| 72 |
+ return false |
|
| 73 |
+ } |
|
| 74 |
+ c.WalkNetworks(l) |
|
| 75 |
+ |
|
| 76 |
+ return list |
|
| 77 |
+} |
|
| 78 |
+ |
|
| 79 |
+// CreateNetwork creates a network with the given name, driver and other optional parameters |
|
| 80 |
+func (daemon *Daemon) CreateNetwork(name, driver string, options map[string]interface{}) (libnetwork.Network, error) {
|
|
| 81 |
+ c := daemon.netController |
|
| 82 |
+ if driver == "" {
|
|
| 83 |
+ driver = c.Config().Daemon.DefaultDriver |
|
| 84 |
+ } |
|
| 85 |
+ |
|
| 86 |
+ if options == nil {
|
|
| 87 |
+ options = make(map[string]interface{})
|
|
| 88 |
+ } |
|
| 89 |
+ _, ok := options[netlabel.GenericData] |
|
| 90 |
+ if !ok {
|
|
| 91 |
+ options[netlabel.GenericData] = make(map[string]interface{})
|
|
| 92 |
+ } |
|
| 93 |
+ |
|
| 94 |
+ return c.NewNetwork(driver, name, parseOptions(options)...) |
|
| 95 |
+} |
|
| 96 |
+ |
|
| 97 |
+func parseOptions(options map[string]interface{}) []libnetwork.NetworkOption {
|
|
| 98 |
+ var setFctList []libnetwork.NetworkOption |
|
| 99 |
+ |
|
| 100 |
+ if options != nil {
|
|
| 101 |
+ setFctList = append(setFctList, libnetwork.NetworkOptionGeneric(options)) |
|
| 102 |
+ } |
|
| 103 |
+ |
|
| 104 |
+ return setFctList |
|
| 105 |
+} |
| ... | ... |
@@ -1,72 +1,201 @@ |
| 1 |
-// +build experimental |
|
| 2 |
- |
|
| 3 | 1 |
package main |
| 4 | 2 |
|
| 5 | 3 |
import ( |
| 6 | 4 |
"encoding/json" |
| 7 |
- "fmt" |
|
| 5 |
+ "net" |
|
| 8 | 6 |
"net/http" |
| 7 |
+ "net/url" |
|
| 8 |
+ "strings" |
|
| 9 | 9 |
|
| 10 |
+ "github.com/docker/docker/api/types" |
|
| 11 |
+ "github.com/docker/docker/pkg/parsers/filters" |
|
| 10 | 12 |
"github.com/go-check/check" |
| 11 | 13 |
) |
| 12 | 14 |
|
| 15 |
+func (s *DockerSuite) TestApiNetworkGetDefaults(c *check.C) {
|
|
| 16 |
+ // By default docker daemon creates 3 networks. check if they are present |
|
| 17 |
+ defaults := []string{"bridge", "host", "none"}
|
|
| 18 |
+ for _, nn := range defaults {
|
|
| 19 |
+ c.Assert(isNetworkAvailable(c, nn), check.Equals, true) |
|
| 20 |
+ } |
|
| 21 |
+} |
|
| 22 |
+ |
|
| 23 |
+func (s *DockerSuite) TestApiNetworkCreateDelete(c *check.C) {
|
|
| 24 |
+ // Create a network |
|
| 25 |
+ name := "testnetwork" |
|
| 26 |
+ id := createNetwork(c, name, true) |
|
| 27 |
+ c.Assert(isNetworkAvailable(c, name), check.Equals, true) |
|
| 28 |
+ |
|
| 29 |
+ // POST another network with same name and CheckDuplicate must fail |
|
| 30 |
+ createNetwork(c, name, false) |
|
| 31 |
+ |
|
| 32 |
+ // delete the network and make sure it is deleted |
|
| 33 |
+ deleteNetwork(c, id, true) |
|
| 34 |
+ c.Assert(isNetworkAvailable(c, name), check.Equals, false) |
|
| 35 |
+} |
|
| 36 |
+ |
|
| 37 |
+func (s *DockerSuite) TestApiNetworkFilter(c *check.C) {
|
|
| 38 |
+ nr := getNetworkResource(c, getNetworkIDByName(c, "bridge")) |
|
| 39 |
+ c.Assert(nr.Name, check.Equals, "bridge") |
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+func (s *DockerSuite) TestApiNetworkInspect(c *check.C) {
|
|
| 43 |
+ // Inspect default bridge network |
|
| 44 |
+ nr := getNetworkResource(c, "bridge") |
|
| 45 |
+ c.Assert(nr.Name, check.Equals, "bridge") |
|
| 46 |
+ |
|
| 47 |
+ // run a container and attach it to the default bridge network |
|
| 48 |
+ out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top") |
|
| 49 |
+ containerID := strings.TrimSpace(out) |
|
| 50 |
+ containerIP := findContainerIP(c, "test") |
|
| 51 |
+ |
|
| 52 |
+ // inspect default bridge network again and make sure the container is connected |
|
| 53 |
+ nr = getNetworkResource(c, nr.ID) |
|
| 54 |
+ c.Assert(len(nr.Containers), check.Equals, 1) |
|
| 55 |
+ c.Assert(nr.Containers[containerID], check.NotNil) |
|
| 56 |
+ |
|
| 57 |
+ ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address) |
|
| 58 |
+ c.Assert(err, check.IsNil) |
|
| 59 |
+ c.Assert(ip.String(), check.Equals, containerIP) |
|
| 60 |
+} |
|
| 61 |
+ |
|
| 62 |
+func (s *DockerSuite) TestApiNetworkConnectDisconnect(c *check.C) {
|
|
| 63 |
+ // Create test network |
|
| 64 |
+ name := "testnetwork" |
|
| 65 |
+ id := createNetwork(c, name, true) |
|
| 66 |
+ nr := getNetworkResource(c, id) |
|
| 67 |
+ c.Assert(nr.Name, check.Equals, name) |
|
| 68 |
+ c.Assert(nr.ID, check.Equals, id) |
|
| 69 |
+ c.Assert(len(nr.Containers), check.Equals, 0) |
|
| 70 |
+ |
|
| 71 |
+ // run a container |
|
| 72 |
+ out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top") |
|
| 73 |
+ containerID := strings.TrimSpace(out) |
|
| 74 |
+ |
|
| 75 |
+ // connect the container to the test network |
|
| 76 |
+ connectNetwork(c, nr.ID, containerID) |
|
| 77 |
+ |
|
| 78 |
+ // inspect the network to make sure container is connected |
|
| 79 |
+ nr = getNetworkResource(c, nr.ID) |
|
| 80 |
+ c.Assert(len(nr.Containers), check.Equals, 1) |
|
| 81 |
+ c.Assert(nr.Containers[containerID], check.NotNil) |
|
| 82 |
+ |
|
| 83 |
+ // check if container IP matches network inspect |
|
| 84 |
+ ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address) |
|
| 85 |
+ c.Assert(err, check.IsNil) |
|
| 86 |
+ containerIP := findContainerIP(c, "test") |
|
| 87 |
+ c.Assert(ip.String(), check.Equals, containerIP) |
|
| 88 |
+ |
|
| 89 |
+ // disconnect container from the network |
|
| 90 |
+ disconnectNetwork(c, nr.ID, containerID) |
|
| 91 |
+ nr = getNetworkResource(c, nr.ID) |
|
| 92 |
+ c.Assert(nr.Name, check.Equals, name) |
|
| 93 |
+ c.Assert(len(nr.Containers), check.Equals, 0) |
|
| 94 |
+ |
|
| 95 |
+ // delete the network |
|
| 96 |
+ deleteNetwork(c, nr.ID, true) |
|
| 97 |
+} |
|
| 98 |
+ |
|
| 13 | 99 |
func isNetworkAvailable(c *check.C, name string) bool {
|
| 14 | 100 |
status, body, err := sockRequest("GET", "/networks", nil)
|
| 15 | 101 |
c.Assert(status, check.Equals, http.StatusOK) |
| 16 | 102 |
c.Assert(err, check.IsNil) |
| 17 | 103 |
|
| 18 |
- var inspectJSON []struct {
|
|
| 19 |
- Name string |
|
| 20 |
- ID string |
|
| 21 |
- Type string |
|
| 22 |
- } |
|
| 23 |
- if err = json.Unmarshal(body, &inspectJSON); err != nil {
|
|
| 24 |
- c.Fatalf("unable to unmarshal response body: %v", err)
|
|
| 25 |
- } |
|
| 26 |
- for _, n := range inspectJSON {
|
|
| 104 |
+ nJSON := []types.NetworkResource{}
|
|
| 105 |
+ err = json.Unmarshal(body, &nJSON) |
|
| 106 |
+ c.Assert(err, check.IsNil) |
|
| 107 |
+ |
|
| 108 |
+ for _, n := range nJSON {
|
|
| 27 | 109 |
if n.Name == name {
|
| 28 | 110 |
return true |
| 29 | 111 |
} |
| 30 | 112 |
} |
| 31 | 113 |
return false |
| 114 |
+} |
|
| 115 |
+ |
|
| 116 |
+func getNetworkIDByName(c *check.C, name string) string {
|
|
| 117 |
+ var ( |
|
| 118 |
+ v = url.Values{}
|
|
| 119 |
+ filterArgs = filters.Args{}
|
|
| 120 |
+ ) |
|
| 121 |
+ filterArgs["name"] = []string{name}
|
|
| 122 |
+ filterJSON, err := filters.ToParam(filterArgs) |
|
| 123 |
+ c.Assert(err, check.IsNil) |
|
| 124 |
+ v.Set("filters", filterJSON)
|
|
| 125 |
+ |
|
| 126 |
+ status, body, err := sockRequest("GET", "/networks?"+v.Encode(), nil)
|
|
| 127 |
+ c.Assert(status, check.Equals, http.StatusOK) |
|
| 128 |
+ c.Assert(err, check.IsNil) |
|
| 129 |
+ |
|
| 130 |
+ nJSON := []types.NetworkResource{}
|
|
| 131 |
+ err = json.Unmarshal(body, &nJSON) |
|
| 132 |
+ c.Assert(err, check.IsNil) |
|
| 133 |
+ c.Assert(len(nJSON), check.Equals, 1) |
|
| 32 | 134 |
|
| 135 |
+ return nJSON[0].ID |
|
| 33 | 136 |
} |
| 34 | 137 |
|
| 35 |
-func (s *DockerSuite) TestNetworkApiGetAll(c *check.C) {
|
|
| 36 |
- defaults := []string{"bridge", "host", "none"}
|
|
| 37 |
- for _, nn := range defaults {
|
|
| 38 |
- if !isNetworkAvailable(c, nn) {
|
|
| 39 |
- c.Fatalf("Missing Default network : %s", nn)
|
|
| 40 |
- } |
|
| 41 |
- } |
|
| 138 |
+func getNetworkResource(c *check.C, id string) *types.NetworkResource {
|
|
| 139 |
+ _, obj, err := sockRequest("GET", "/networks/"+id, nil)
|
|
| 140 |
+ c.Assert(err, check.IsNil) |
|
| 141 |
+ |
|
| 142 |
+ nr := types.NetworkResource{}
|
|
| 143 |
+ err = json.Unmarshal(obj, &nr) |
|
| 144 |
+ c.Assert(err, check.IsNil) |
|
| 145 |
+ |
|
| 146 |
+ return &nr |
|
| 42 | 147 |
} |
| 43 | 148 |
|
| 44 |
-func (s *DockerSuite) TestNetworkApiCreateDelete(c *check.C) {
|
|
| 45 |
- name := "testnetwork" |
|
| 46 |
- config := map[string]interface{}{
|
|
| 47 |
- "name": name, |
|
| 48 |
- "network_type": "bridge", |
|
| 149 |
+func createNetwork(c *check.C, name string, shouldSucceed bool) string {
|
|
| 150 |
+ config := types.NetworkCreate{
|
|
| 151 |
+ Name: name, |
|
| 152 |
+ Driver: "bridge", |
|
| 153 |
+ CheckDuplicate: true, |
|
| 154 |
+ } |
|
| 155 |
+ |
|
| 156 |
+ status, resp, err := sockRequest("POST", "/networks/create", config)
|
|
| 157 |
+ if !shouldSucceed {
|
|
| 158 |
+ c.Assert(status, check.Not(check.Equals), http.StatusCreated) |
|
| 159 |
+ return "" |
|
| 49 | 160 |
} |
| 50 | 161 |
|
| 51 |
- status, resp, err := sockRequest("POST", "/networks", config)
|
|
| 52 | 162 |
c.Assert(status, check.Equals, http.StatusCreated) |
| 53 | 163 |
c.Assert(err, check.IsNil) |
| 54 | 164 |
|
| 55 |
- if !isNetworkAvailable(c, name) {
|
|
| 56 |
- c.Fatalf("Network %s not found", name)
|
|
| 165 |
+ var nr types.NetworkCreateResponse |
|
| 166 |
+ err = json.Unmarshal(resp, &nr) |
|
| 167 |
+ c.Assert(err, check.IsNil) |
|
| 168 |
+ |
|
| 169 |
+ return nr.ID |
|
| 170 |
+} |
|
| 171 |
+ |
|
| 172 |
+func connectNetwork(c *check.C, nid, cid string) {
|
|
| 173 |
+ config := types.NetworkConnect{
|
|
| 174 |
+ Container: cid, |
|
| 57 | 175 |
} |
| 58 | 176 |
|
| 59 |
- var id string |
|
| 60 |
- err = json.Unmarshal(resp, &id) |
|
| 61 |
- if err != nil {
|
|
| 62 |
- c.Fatal(err) |
|
| 177 |
+ status, _, err := sockRequest("POST", "/networks/"+nid+"/connect", config)
|
|
| 178 |
+ c.Assert(status, check.Equals, http.StatusOK) |
|
| 179 |
+ c.Assert(err, check.IsNil) |
|
| 180 |
+} |
|
| 181 |
+ |
|
| 182 |
+func disconnectNetwork(c *check.C, nid, cid string) {
|
|
| 183 |
+ config := types.NetworkConnect{
|
|
| 184 |
+ Container: cid, |
|
| 63 | 185 |
} |
| 64 | 186 |
|
| 65 |
- status, _, err = sockRequest("DELETE", fmt.Sprintf("/networks/%s", id), nil)
|
|
| 187 |
+ status, _, err := sockRequest("POST", "/networks/"+nid+"/disconnect", config)
|
|
| 66 | 188 |
c.Assert(status, check.Equals, http.StatusOK) |
| 67 | 189 |
c.Assert(err, check.IsNil) |
| 190 |
+} |
|
| 68 | 191 |
|
| 69 |
- if isNetworkAvailable(c, name) {
|
|
| 70 |
- c.Fatalf("Network %s not deleted", name)
|
|
| 192 |
+func deleteNetwork(c *check.C, id string, shouldSucceed bool) {
|
|
| 193 |
+ status, _, err := sockRequest("DELETE", "/networks/"+id, nil)
|
|
| 194 |
+ if !shouldSucceed {
|
|
| 195 |
+ c.Assert(status, check.Not(check.Equals), http.StatusOK) |
|
| 196 |
+ c.Assert(err, check.NotNil) |
|
| 197 |
+ return |
|
| 71 | 198 |
} |
| 199 |
+ c.Assert(status, check.Equals, http.StatusOK) |
|
| 200 |
+ c.Assert(err, check.IsNil) |
|
| 72 | 201 |
} |
| 73 | 202 |
deleted file mode 100644 |
| ... | ... |
@@ -1,40 +0,0 @@ |
| 1 |
-// +build daemon,experimental,!windows |
|
| 2 |
- |
|
| 3 |
-package main |
|
| 4 |
- |
|
| 5 |
-import ( |
|
| 6 |
- "os/exec" |
|
| 7 |
- "strings" |
|
| 8 |
- |
|
| 9 |
- "github.com/go-check/check" |
|
| 10 |
-) |
|
| 11 |
- |
|
| 12 |
-func assertNetwork(c *check.C, d *Daemon, name string) {
|
|
| 13 |
- out, err := d.Cmd("network", "ls")
|
|
| 14 |
- c.Assert(err, check.IsNil) |
|
| 15 |
- lines := strings.Split(out, "\n") |
|
| 16 |
- for i := 1; i < len(lines)-1; i++ {
|
|
| 17 |
- if strings.Contains(lines[i], name) {
|
|
| 18 |
- return |
|
| 19 |
- } |
|
| 20 |
- } |
|
| 21 |
- c.Fatalf("Network %s not found in network ls o/p", name)
|
|
| 22 |
-} |
|
| 23 |
- |
|
| 24 |
-func (s *DockerDaemonSuite) TestDaemonDefaultNetwork(c *check.C) {
|
|
| 25 |
- testRequires(c, SameHostDaemon) |
|
| 26 |
- d := s.d |
|
| 27 |
- |
|
| 28 |
- networkName := "testdefault" |
|
| 29 |
- err := d.StartWithBusybox("--default-network", "bridge:"+networkName)
|
|
| 30 |
- c.Assert(err, check.IsNil) |
|
| 31 |
- |
|
| 32 |
- _, err = d.Cmd("run", "busybox", "true")
|
|
| 33 |
- c.Assert(err, check.IsNil) |
|
| 34 |
- |
|
| 35 |
- assertNetwork(c, d, networkName) |
|
| 36 |
- |
|
| 37 |
- ifconfigCmd := exec.Command("ifconfig", networkName)
|
|
| 38 |
- _, _, _, err = runCommandWithStdoutStderr(ifconfigCmd) |
|
| 39 |
- c.Assert(err, check.IsNil) |
|
| 40 |
-} |
| ... | ... |
@@ -77,7 +77,7 @@ func (s *DockerSuite) TestNetHostname(c *check.C) {
|
| 77 | 77 |
if out, _, err = runCommandWithOutput(runCmd); err == nil {
|
| 78 | 78 |
c.Fatalf(out, err) |
| 79 | 79 |
} |
| 80 |
- checkContains("invalid --net: weird", out, c)
|
|
| 80 |
+ checkContains("network weird not found", out, c)
|
|
| 81 | 81 |
} |
| 82 | 82 |
|
| 83 | 83 |
func (s *DockerSuite) TestConflictContainerNetworkAndLinks(c *check.C) {
|
| ... | ... |
@@ -3168,7 +3168,7 @@ func (s *DockerSuite) TestRunCreateContainerFailedCleanUp(c *check.C) {
|
| 3168 | 3168 |
testRequires(c, DaemonIsLinux) |
| 3169 | 3169 |
name := "unique_name" |
| 3170 | 3170 |
_, _, err := dockerCmdWithError("run", "--name", name, "--link", "nothing:nothing", "busybox")
|
| 3171 |
- c.Assert(err, check.Not(check.IsNil), check.Commentf("Expected docker run to fail!"))
|
|
| 3171 |
+ c.Assert(err, check.NotNil, check.Commentf("Expected docker run to fail!"))
|
|
| 3172 | 3172 |
|
| 3173 | 3173 |
containerID, err := inspectField(name, "Id") |
| 3174 | 3174 |
c.Assert(containerID, check.Equals, "", check.Commentf("Expected not to have this container: %s!", containerID))
|
| ... | ... |
@@ -3404,6 +3404,154 @@ func (s *DockerSuite) TestTwoContainersInNetHost(c *check.C) {
|
| 3404 | 3404 |
dockerCmd(c, "stop", "second") |
| 3405 | 3405 |
} |
| 3406 | 3406 |
|
| 3407 |
+func (s *DockerSuite) TestContainersInUserDefinedNetwork(c *check.C) {
|
|
| 3408 |
+ testRequires(c, DaemonIsLinux) |
|
| 3409 |
+ dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork") |
|
| 3410 |
+ dockerCmd(c, "run", "-d", "--net=testnetwork", "--name=first", "busybox", "top") |
|
| 3411 |
+ dockerCmd(c, "run", "-t", "--net=testnetwork", "--name=second", "busybox", "ping", "-c", "1", "first") |
|
| 3412 |
+ dockerCmd(c, "stop", "first") |
|
| 3413 |
+ dockerCmd(c, "stop", "second") |
|
| 3414 |
+ dockerCmd(c, "network", "rm", "testnetwork") |
|
| 3415 |
+} |
|
| 3416 |
+ |
|
| 3417 |
+func (s *DockerSuite) TestContainersInMultipleNetworks(c *check.C) {
|
|
| 3418 |
+ testRequires(c, DaemonIsLinux) |
|
| 3419 |
+ // Create 2 networks using bridge driver |
|
| 3420 |
+ dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") |
|
| 3421 |
+ dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2") |
|
| 3422 |
+ // Run and connect containers to testnetwork1 |
|
| 3423 |
+ dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top") |
|
| 3424 |
+ dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top") |
|
| 3425 |
+ // Check connectivity between containers in testnetwork2 |
|
| 3426 |
+ dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1") |
|
| 3427 |
+ // Connect containers to testnetwork2 |
|
| 3428 |
+ dockerCmd(c, "network", "connect", "testnetwork2", "first") |
|
| 3429 |
+ dockerCmd(c, "network", "connect", "testnetwork2", "second") |
|
| 3430 |
+ // Check connectivity between containers |
|
| 3431 |
+ dockerCmd(c, "exec", "second", "ping", "-c", "1", "first.testnetwork2") |
|
| 3432 |
+ dockerCmd(c, "stop", "first") |
|
| 3433 |
+ dockerCmd(c, "stop", "second") |
|
| 3434 |
+ dockerCmd(c, "network", "rm", "testnetwork1") |
|
| 3435 |
+ dockerCmd(c, "network", "rm", "testnetwork2") |
|
| 3436 |
+} |
|
| 3437 |
+ |
|
| 3438 |
+func (s *DockerSuite) TestContainersNetworkIsolation(c *check.C) {
|
|
| 3439 |
+ testRequires(c, DaemonIsLinux) |
|
| 3440 |
+ // Create 2 networks using bridge driver |
|
| 3441 |
+ dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") |
|
| 3442 |
+ dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2") |
|
| 3443 |
+ // Run 1 containers in testnetwork1 and another in testnetwork2 |
|
| 3444 |
+ dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top") |
|
| 3445 |
+ dockerCmd(c, "run", "-d", "--net=testnetwork2", "--name=second", "busybox", "top") |
|
| 3446 |
+ |
|
| 3447 |
+ // Check Isolation between containers : ping must fail |
|
| 3448 |
+ _, _, err := dockerCmdWithError("exec", "first", "ping", "-c", "1", "second")
|
|
| 3449 |
+ c.Assert(err, check.NotNil) |
|
| 3450 |
+ // Connect first container to testnetwork2 |
|
| 3451 |
+ dockerCmd(c, "network", "connect", "testnetwork2", "first") |
|
| 3452 |
+ // ping must succeed now |
|
| 3453 |
+ _, _, err = dockerCmdWithError("exec", "first", "ping", "-c", "1", "second")
|
|
| 3454 |
+ c.Assert(err, check.IsNil) |
|
| 3455 |
+ |
|
| 3456 |
+ // Disconnect first container from testnetwork2 |
|
| 3457 |
+ dockerCmd(c, "network", "disconnect", "testnetwork2", "first") |
|
| 3458 |
+ // ping must fail again |
|
| 3459 |
+ _, _, err = dockerCmdWithError("exec", "first", "ping", "-c", "1", "second")
|
|
| 3460 |
+ c.Assert(err, check.NotNil) |
|
| 3461 |
+ |
|
| 3462 |
+ dockerCmd(c, "stop", "first") |
|
| 3463 |
+ dockerCmd(c, "stop", "second") |
|
| 3464 |
+ dockerCmd(c, "network", "rm", "testnetwork1") |
|
| 3465 |
+ dockerCmd(c, "network", "rm", "testnetwork2") |
|
| 3466 |
+} |
|
| 3467 |
+ |
|
| 3468 |
+func (s *DockerSuite) TestNetworkRmWithActiveContainers(c *check.C) {
|
|
| 3469 |
+ testRequires(c, DaemonIsLinux) |
|
| 3470 |
+ // Create 2 networks using bridge driver |
|
| 3471 |
+ dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") |
|
| 3472 |
+ // Run and connect containers to testnetwork1 |
|
| 3473 |
+ dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top") |
|
| 3474 |
+ dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top") |
|
| 3475 |
+ // Network delete with active containers must fail |
|
| 3476 |
+ _, _, err := dockerCmdWithError("network", "rm", "testnetwork1")
|
|
| 3477 |
+ c.Assert(err, check.NotNil) |
|
| 3478 |
+ |
|
| 3479 |
+ dockerCmd(c, "stop", "first") |
|
| 3480 |
+ _, _, err = dockerCmdWithError("network", "rm", "testnetwork1")
|
|
| 3481 |
+ c.Assert(err, check.NotNil) |
|
| 3482 |
+ |
|
| 3483 |
+ dockerCmd(c, "stop", "second") |
|
| 3484 |
+ // Network delete must succeed after all the connected containers are inactive |
|
| 3485 |
+ dockerCmd(c, "network", "rm", "testnetwork1") |
|
| 3486 |
+} |
|
| 3487 |
+ |
|
| 3488 |
+func (s *DockerSuite) TestContainerRestartInMultipleNetworks(c *check.C) {
|
|
| 3489 |
+ testRequires(c, DaemonIsLinux) |
|
| 3490 |
+ // Create 2 networks using bridge driver |
|
| 3491 |
+ dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") |
|
| 3492 |
+ dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork2") |
|
| 3493 |
+ // Run and connect containers to testnetwork1 |
|
| 3494 |
+ dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=first", "busybox", "top") |
|
| 3495 |
+ dockerCmd(c, "run", "-d", "--net=testnetwork1", "--name=second", "busybox", "top") |
|
| 3496 |
+ // Check connectivity between containers in testnetwork2 |
|
| 3497 |
+ dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1") |
|
| 3498 |
+ // Connect containers to testnetwork2 |
|
| 3499 |
+ dockerCmd(c, "network", "connect", "testnetwork2", "first") |
|
| 3500 |
+ dockerCmd(c, "network", "connect", "testnetwork2", "second") |
|
| 3501 |
+ // Check connectivity between containers |
|
| 3502 |
+ dockerCmd(c, "exec", "second", "ping", "-c", "1", "first.testnetwork2") |
|
| 3503 |
+ |
|
| 3504 |
+ // Stop second container and test ping failures on both networks |
|
| 3505 |
+ dockerCmd(c, "stop", "second") |
|
| 3506 |
+ _, _, err := dockerCmdWithError("exec", "first", "ping", "-c", "1", "second.testnetwork1")
|
|
| 3507 |
+ c.Assert(err, check.NotNil) |
|
| 3508 |
+ _, _, err = dockerCmdWithError("exec", "first", "ping", "-c", "1", "second.testnetwork2")
|
|
| 3509 |
+ c.Assert(err, check.NotNil) |
|
| 3510 |
+ |
|
| 3511 |
+ // Start second container and connectivity must be restored on both networks |
|
| 3512 |
+ dockerCmd(c, "start", "second") |
|
| 3513 |
+ dockerCmd(c, "exec", "first", "ping", "-c", "1", "second.testnetwork1") |
|
| 3514 |
+ dockerCmd(c, "exec", "second", "ping", "-c", "1", "first.testnetwork2") |
|
| 3515 |
+ |
|
| 3516 |
+ dockerCmd(c, "stop", "first") |
|
| 3517 |
+ dockerCmd(c, "stop", "second") |
|
| 3518 |
+ dockerCmd(c, "network", "rm", "testnetwork1") |
|
| 3519 |
+ dockerCmd(c, "network", "rm", "testnetwork2") |
|
| 3520 |
+} |
|
| 3521 |
+ |
|
| 3522 |
+func (s *DockerSuite) TestContainerWithConflictingHostNetworks(c *check.C) {
|
|
| 3523 |
+ testRequires(c, DaemonIsLinux) |
|
| 3524 |
+ // Run a container with --net=host |
|
| 3525 |
+ dockerCmd(c, "run", "-d", "--net=host", "--name=first", "busybox", "top") |
|
| 3526 |
+ |
|
| 3527 |
+ // Create a network using bridge driver |
|
| 3528 |
+ dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") |
|
| 3529 |
+ |
|
| 3530 |
+ // Connecting to the user defined network must fail |
|
| 3531 |
+ _, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "first")
|
|
| 3532 |
+ c.Assert(err, check.NotNil) |
|
| 3533 |
+ dockerCmd(c, "stop", "first") |
|
| 3534 |
+ dockerCmd(c, "network", "rm", "testnetwork1") |
|
| 3535 |
+} |
|
| 3536 |
+ |
|
| 3537 |
+func (s *DockerSuite) TestContainerWithConflictingSharedNetwork(c *check.C) {
|
|
| 3538 |
+ testRequires(c, DaemonIsLinux) |
|
| 3539 |
+ dockerCmd(c, "run", "-d", "--name=first", "busybox", "top") |
|
| 3540 |
+ // Run second container in first container's network namespace |
|
| 3541 |
+ dockerCmd(c, "run", "-d", "--net=container:first", "--name=second", "busybox", "top") |
|
| 3542 |
+ |
|
| 3543 |
+ // Create a network using bridge driver |
|
| 3544 |
+ dockerCmd(c, "network", "create", "-d", "bridge", "testnetwork1") |
|
| 3545 |
+ |
|
| 3546 |
+ // Connecting to the user defined network must fail |
|
| 3547 |
+ _, _, err := dockerCmdWithError("network", "connect", "testnetwork1", "second")
|
|
| 3548 |
+ c.Assert(err, check.NotNil) |
|
| 3549 |
+ |
|
| 3550 |
+ dockerCmd(c, "stop", "first") |
|
| 3551 |
+ dockerCmd(c, "stop", "second") |
|
| 3552 |
+ dockerCmd(c, "network", "rm", "testnetwork1") |
|
| 3553 |
+} |
|
| 3554 |
+ |
|
| 3407 | 3555 |
// #11957 - stdin with no tty does not exit if stdin is not closed even though container exited |
| 3408 | 3556 |
func (s *DockerSuite) TestRunStdinBlockedAfterContainerExit(c *check.C) {
|
| 3409 | 3557 |
cmd := exec.Command(dockerBinary, "run", "-i", "--name=test", "busybox", "true") |
| ... | ... |
@@ -20,7 +20,6 @@ type Config struct {
|
| 20 | 20 |
AttachStdout bool // Attach the standard output |
| 21 | 21 |
AttachStderr bool // Attach the standard error |
| 22 | 22 |
ExposedPorts map[nat.Port]struct{} // List of exposed ports
|
| 23 |
- PublishService string // Name of the network service exposed by the container |
|
| 24 | 23 |
Tty bool // Attach standard streams to a tty, including stdin if it is not closed. |
| 25 | 24 |
OpenStdin bool // Open stdin |
| 26 | 25 |
StdinOnce bool // If true, close stdin after the 1 attached client disconnects. |
| ... | ... |
@@ -24,7 +24,7 @@ func TestNetworkModeTest(t *testing.T) {
|
| 24 | 24 |
} |
| 25 | 25 |
networkModeNames := map[NetworkMode]string{
|
| 26 | 26 |
"": "", |
| 27 |
- "something:weird": "", |
|
| 27 |
+ "something:weird": "something:weird", |
|
| 28 | 28 |
"bridge": "bridge", |
| 29 | 29 |
DefaultDaemonNetworkMode(): "bridge", |
| 30 | 30 |
"host": "host", |
| ... | ... |
@@ -34,6 +34,8 @@ func (n NetworkMode) NetworkName() string {
|
| 34 | 34 |
return "none" |
| 35 | 35 |
} else if n.IsDefault() {
|
| 36 | 36 |
return "default" |
| 37 |
+ } else if n.IsUserDefined() {
|
|
| 38 |
+ return n.UserDefined() |
|
| 37 | 39 |
} |
| 38 | 40 |
return "" |
| 39 | 41 |
} |
| ... | ... |
@@ -59,6 +61,19 @@ func (n NetworkMode) IsNone() bool {
|
| 59 | 59 |
return n == "none" |
| 60 | 60 |
} |
| 61 | 61 |
|
| 62 |
+// IsUserDefined indicates user-created network |
|
| 63 |
+func (n NetworkMode) IsUserDefined() bool {
|
|
| 64 |
+ return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() |
|
| 65 |
+} |
|
| 66 |
+ |
|
| 67 |
+//UserDefined indicates user-created network |
|
| 68 |
+func (n NetworkMode) UserDefined() string {
|
|
| 69 |
+ if n.IsUserDefined() {
|
|
| 70 |
+ return string(n) |
|
| 71 |
+ } |
|
| 72 |
+ return "" |
|
| 73 |
+} |
|
| 74 |
+ |
|
| 62 | 75 |
// MergeConfigs merges the specified container Config and HostConfig. |
| 63 | 76 |
// It creates a ContainerConfigWrapper. |
| 64 | 77 |
func MergeConfigs(config *Config, hostConfig *HostConfig) *ContainerConfigWrapper {
|
| ... | ... |
@@ -17,6 +17,12 @@ import ( |
| 17 | 17 |
var ( |
| 18 | 18 |
// ErrConflictContainerNetworkAndLinks conflict between --net=container and links |
| 19 | 19 |
ErrConflictContainerNetworkAndLinks = fmt.Errorf("Conflicting options: --net=container can't be used with links. This would result in undefined behavior")
|
| 20 |
+ // ErrConflictUserDefinedNetworkAndLinks conflict between --net=<NETWORK> and links |
|
| 21 |
+ ErrConflictUserDefinedNetworkAndLinks = fmt.Errorf("Conflicting options: --net=<NETWORK> can't be used with links. This would result in undefined behavior")
|
|
| 22 |
+ // ErrConflictSharedNetwork conflict between private and other networks |
|
| 23 |
+ ErrConflictSharedNetwork = fmt.Errorf("Container sharing network namespace with another container or host cannot be connected to any other network")
|
|
| 24 |
+ // ErrConflictNoNetwork conflict between private and other networks |
|
| 25 |
+ ErrConflictNoNetwork = fmt.Errorf("Container cannot be connected to multiple networks with one of the networks in --none mode")
|
|
| 20 | 26 |
// ErrConflictNetworkAndDNS conflict between --dns and the network mode |
| 21 | 27 |
ErrConflictNetworkAndDNS = fmt.Errorf("Conflicting options: --dns and the network mode (--net)")
|
| 22 | 28 |
// ErrConflictNetworkHostname conflict between the hostname and the network mode |
| ... | ... |
@@ -88,7 +94,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe |
| 88 | 88 |
flCpusetMems = cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
|
| 89 | 89 |
flBlkioWeight = cmd.Int64([]string{"-blkio-weight"}, 0, "Block IO (relative weight), between 10 and 1000")
|
| 90 | 90 |
flSwappiness = cmd.Int64([]string{"-memory-swappiness"}, -1, "Tuning container memory swappiness (0 to 100)")
|
| 91 |
- flNetMode = cmd.String([]string{"-net"}, "default", "Set the Network mode for the container")
|
|
| 91 |
+ flNetMode = cmd.String([]string{"-net"}, "default", "Set the Network for the container")
|
|
| 92 | 92 |
flMacAddress = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)")
|
| 93 | 93 |
flIpcMode = cmd.String([]string{"-ipc"}, "", "IPC namespace to use")
|
| 94 | 94 |
flRestartPolicy = cmd.String([]string{"-restart"}, "no", "Restart policy to apply when a container exits")
|
| ... | ... |
@@ -122,8 +128,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe |
| 122 | 122 |
cmd.Var(flUlimits, []string{"-ulimit"}, "Ulimit options")
|
| 123 | 123 |
cmd.Var(&flLoggingOpts, []string{"-log-opt"}, "Log driver options")
|
| 124 | 124 |
|
| 125 |
- expFlags := attachExperimentalFlags(cmd) |
|
| 126 |
- |
|
| 127 | 125 |
cmd.Require(flag.Min, 1) |
| 128 | 126 |
|
| 129 | 127 |
if err := cmd.ParseFlags(args, true); err != nil {
|
| ... | ... |
@@ -379,8 +383,6 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe |
| 379 | 379 |
VolumeDriver: *flVolumeDriver, |
| 380 | 380 |
} |
| 381 | 381 |
|
| 382 |
- applyExperimentalFlags(expFlags, config, hostConfig) |
|
| 383 |
- |
|
| 384 | 382 |
// When allocating stdin in attached mode, close stdin at client disconnect |
| 385 | 383 |
if config.OpenStdin && config.AttachStdin {
|
| 386 | 384 |
config.StdinOnce = true |
| 387 | 385 |
deleted file mode 100644 |
| ... | ... |
@@ -1,19 +0,0 @@ |
| 1 |
-// +build experimental |
|
| 2 |
- |
|
| 3 |
-package runconfig |
|
| 4 |
- |
|
| 5 |
-import flag "github.com/docker/docker/pkg/mflag" |
|
| 6 |
- |
|
| 7 |
-type experimentalFlags struct {
|
|
| 8 |
- flags map[string]interface{}
|
|
| 9 |
-} |
|
| 10 |
- |
|
| 11 |
-func attachExperimentalFlags(cmd *flag.FlagSet) *experimentalFlags {
|
|
| 12 |
- flags := make(map[string]interface{})
|
|
| 13 |
- flags["publish-service"] = cmd.String([]string{"-publish-service"}, "", "Publish this container as a service")
|
|
| 14 |
- return &experimentalFlags{flags: flags}
|
|
| 15 |
-} |
|
| 16 |
- |
|
| 17 |
-func applyExperimentalFlags(exp *experimentalFlags, config *Config, hostConfig *HostConfig) {
|
|
| 18 |
- config.PublishService = *(exp.flags["publish-service"]).(*string) |
|
| 19 |
-} |
| 20 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,14 +0,0 @@ |
| 1 |
-// +build !experimental |
|
| 2 |
- |
|
| 3 |
-package runconfig |
|
| 4 |
- |
|
| 5 |
-import flag "github.com/docker/docker/pkg/mflag" |
|
| 6 |
- |
|
| 7 |
-type experimentalFlags struct{}
|
|
| 8 |
- |
|
| 9 |
-func attachExperimentalFlags(cmd *flag.FlagSet) *experimentalFlags {
|
|
| 10 |
- return nil |
|
| 11 |
-} |
|
| 12 |
- |
|
| 13 |
-func applyExperimentalFlags(flags *experimentalFlags, config *Config, hostConfig *HostConfig) {
|
|
| 14 |
-} |
| ... | ... |
@@ -15,14 +15,10 @@ func ValidateNetMode(c *Config, hc *HostConfig) error {
|
| 15 | 15 |
return nil |
| 16 | 16 |
} |
| 17 | 17 |
parts := strings.Split(string(hc.NetworkMode), ":") |
| 18 |
- switch mode := parts[0]; mode {
|
|
| 19 |
- case "default", "bridge", "none", "host": |
|
| 20 |
- case "container": |
|
| 18 |
+ if parts[0] == "container" {
|
|
| 21 | 19 |
if len(parts) < 2 || parts[1] == "" {
|
| 22 | 20 |
return fmt.Errorf("--net: invalid net mode: invalid container format container:<name|id>")
|
| 23 | 21 |
} |
| 24 |
- default: |
|
| 25 |
- return fmt.Errorf("invalid --net: %s", hc.NetworkMode)
|
|
| 26 | 22 |
} |
| 27 | 23 |
|
| 28 | 24 |
if (hc.NetworkMode.IsHost() || hc.NetworkMode.IsContainer()) && c.Hostname != "" {
|
| ... | ... |
@@ -37,6 +33,10 @@ func ValidateNetMode(c *Config, hc *HostConfig) error {
|
| 37 | 37 |
return ErrConflictContainerNetworkAndLinks |
| 38 | 38 |
} |
| 39 | 39 |
|
| 40 |
+ if hc.NetworkMode.IsUserDefined() && len(hc.Links) > 0 {
|
|
| 41 |
+ return ErrConflictUserDefinedNetworkAndLinks |
|
| 42 |
+ } |
|
| 43 |
+ |
|
| 40 | 44 |
if (hc.NetworkMode.IsHost() || hc.NetworkMode.IsContainer()) && len(hc.DNS) > 0 {
|
| 41 | 45 |
return ErrConflictNetworkAndDNS |
| 42 | 46 |
} |
| 43 | 47 |
deleted file mode 100644 |
| ... | ... |
@@ -1,949 +0,0 @@ |
| 1 |
-package api |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "encoding/json" |
|
| 5 |
- "fmt" |
|
| 6 |
- "io/ioutil" |
|
| 7 |
- "net/http" |
|
| 8 |
- "strings" |
|
| 9 |
- |
|
| 10 |
- "github.com/docker/libnetwork" |
|
| 11 |
- "github.com/docker/libnetwork/netlabel" |
|
| 12 |
- "github.com/docker/libnetwork/types" |
|
| 13 |
- "github.com/gorilla/mux" |
|
| 14 |
-) |
|
| 15 |
- |
|
| 16 |
-var ( |
|
| 17 |
- successResponse = responseStatus{Status: "Success", StatusCode: http.StatusOK}
|
|
| 18 |
- createdResponse = responseStatus{Status: "Created", StatusCode: http.StatusCreated}
|
|
| 19 |
- mismatchResponse = responseStatus{Status: "Body/URI parameter mismatch", StatusCode: http.StatusBadRequest}
|
|
| 20 |
- badQueryResponse = responseStatus{Status: "Unsupported query", StatusCode: http.StatusBadRequest}
|
|
| 21 |
-) |
|
| 22 |
- |
|
| 23 |
-const ( |
|
| 24 |
- // Resource name regex |
|
| 25 |
- // Gorilla mux encloses the passed pattern with '^' and '$'. So we need to do some tricks |
|
| 26 |
- // to have mux eventually build a query regex which matches empty or word string (`^$|[\w]+`) |
|
| 27 |
- regex = "[a-zA-Z_0-9-]+" |
|
| 28 |
- qregx = "$|" + regex |
|
| 29 |
- // Router URL variable definition |
|
| 30 |
- nwName = "{" + urlNwName + ":" + regex + "}"
|
|
| 31 |
- nwNameQr = "{" + urlNwName + ":" + qregx + "}"
|
|
| 32 |
- nwID = "{" + urlNwID + ":" + regex + "}"
|
|
| 33 |
- nwPIDQr = "{" + urlNwPID + ":" + qregx + "}"
|
|
| 34 |
- epName = "{" + urlEpName + ":" + regex + "}"
|
|
| 35 |
- epNameQr = "{" + urlEpName + ":" + qregx + "}"
|
|
| 36 |
- epID = "{" + urlEpID + ":" + regex + "}"
|
|
| 37 |
- epPIDQr = "{" + urlEpPID + ":" + qregx + "}"
|
|
| 38 |
- sbID = "{" + urlSbID + ":" + regex + "}"
|
|
| 39 |
- sbPIDQr = "{" + urlSbPID + ":" + qregx + "}"
|
|
| 40 |
- cnIDQr = "{" + urlCnID + ":" + qregx + "}"
|
|
| 41 |
- cnPIDQr = "{" + urlCnPID + ":" + qregx + "}"
|
|
| 42 |
- |
|
| 43 |
- // Internal URL variable name.They can be anything as |
|
| 44 |
- // long as they do not collide with query fields. |
|
| 45 |
- urlNwName = "network-name" |
|
| 46 |
- urlNwID = "network-id" |
|
| 47 |
- urlNwPID = "network-partial-id" |
|
| 48 |
- urlEpName = "endpoint-name" |
|
| 49 |
- urlEpID = "endpoint-id" |
|
| 50 |
- urlEpPID = "endpoint-partial-id" |
|
| 51 |
- urlSbID = "sandbox-id" |
|
| 52 |
- urlSbPID = "sandbox-partial-id" |
|
| 53 |
- urlCnID = "container-id" |
|
| 54 |
- urlCnPID = "container-partial-id" |
|
| 55 |
- |
|
| 56 |
- // BridgeNetworkDriver is the built-in default for Network Driver |
|
| 57 |
- BridgeNetworkDriver = "bridge" |
|
| 58 |
-) |
|
| 59 |
- |
|
| 60 |
-// NewHTTPHandler creates and initialize the HTTP handler to serve the requests for libnetwork |
|
| 61 |
-func NewHTTPHandler(c libnetwork.NetworkController) func(w http.ResponseWriter, req *http.Request) {
|
|
| 62 |
- h := &httpHandler{c: c}
|
|
| 63 |
- h.initRouter() |
|
| 64 |
- return h.handleRequest |
|
| 65 |
-} |
|
| 66 |
- |
|
| 67 |
-type responseStatus struct {
|
|
| 68 |
- Status string |
|
| 69 |
- StatusCode int |
|
| 70 |
-} |
|
| 71 |
- |
|
| 72 |
-func (r *responseStatus) isOK() bool {
|
|
| 73 |
- return r.StatusCode == http.StatusOK || r.StatusCode == http.StatusCreated |
|
| 74 |
-} |
|
| 75 |
- |
|
| 76 |
-type processor func(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus)
|
|
| 77 |
- |
|
| 78 |
-type httpHandler struct {
|
|
| 79 |
- c libnetwork.NetworkController |
|
| 80 |
- r *mux.Router |
|
| 81 |
-} |
|
| 82 |
- |
|
| 83 |
-func (h *httpHandler) handleRequest(w http.ResponseWriter, req *http.Request) {
|
|
| 84 |
- // Make sure the service is there |
|
| 85 |
- if h.c == nil {
|
|
| 86 |
- http.Error(w, "NetworkController is not available", http.StatusServiceUnavailable) |
|
| 87 |
- return |
|
| 88 |
- } |
|
| 89 |
- |
|
| 90 |
- // Get handler from router and execute it |
|
| 91 |
- h.r.ServeHTTP(w, req) |
|
| 92 |
-} |
|
| 93 |
- |
|
| 94 |
-func (h *httpHandler) initRouter() {
|
|
| 95 |
- m := map[string][]struct {
|
|
| 96 |
- url string |
|
| 97 |
- qrs []string |
|
| 98 |
- fct processor |
|
| 99 |
- }{
|
|
| 100 |
- "GET": {
|
|
| 101 |
- // Order matters |
|
| 102 |
- {"/networks", []string{"name", nwNameQr}, procGetNetworks},
|
|
| 103 |
- {"/networks", []string{"partial-id", nwPIDQr}, procGetNetworks},
|
|
| 104 |
- {"/networks", nil, procGetNetworks},
|
|
| 105 |
- {"/networks/" + nwID, nil, procGetNetwork},
|
|
| 106 |
- {"/networks/" + nwID + "/endpoints", []string{"name", epNameQr}, procGetEndpoints},
|
|
| 107 |
- {"/networks/" + nwID + "/endpoints", []string{"partial-id", epPIDQr}, procGetEndpoints},
|
|
| 108 |
- {"/networks/" + nwID + "/endpoints", nil, procGetEndpoints},
|
|
| 109 |
- {"/networks/" + nwID + "/endpoints/" + epID, nil, procGetEndpoint},
|
|
| 110 |
- {"/services", []string{"network", nwNameQr}, procGetServices},
|
|
| 111 |
- {"/services", []string{"name", epNameQr}, procGetServices},
|
|
| 112 |
- {"/services", []string{"partial-id", epPIDQr}, procGetServices},
|
|
| 113 |
- {"/services", nil, procGetServices},
|
|
| 114 |
- {"/services/" + epID, nil, procGetService},
|
|
| 115 |
- {"/services/" + epID + "/backend", nil, procGetSandbox},
|
|
| 116 |
- {"/sandboxes", []string{"partial-container-id", cnPIDQr}, procGetSandboxes},
|
|
| 117 |
- {"/sandboxes", []string{"container-id", cnIDQr}, procGetSandboxes},
|
|
| 118 |
- {"/sandboxes", []string{"partial-id", sbPIDQr}, procGetSandboxes},
|
|
| 119 |
- {"/sandboxes", nil, procGetSandboxes},
|
|
| 120 |
- {"/sandboxes/" + sbID, nil, procGetSandbox},
|
|
| 121 |
- }, |
|
| 122 |
- "POST": {
|
|
| 123 |
- {"/networks", nil, procCreateNetwork},
|
|
| 124 |
- {"/networks/" + nwID + "/endpoints", nil, procCreateEndpoint},
|
|
| 125 |
- {"/networks/" + nwID + "/endpoints/" + epID + "/sandboxes", nil, procJoinEndpoint},
|
|
| 126 |
- {"/services", nil, procPublishService},
|
|
| 127 |
- {"/services/" + epID + "/backend", nil, procAttachBackend},
|
|
| 128 |
- {"/sandboxes", nil, procCreateSandbox},
|
|
| 129 |
- }, |
|
| 130 |
- "DELETE": {
|
|
| 131 |
- {"/networks/" + nwID, nil, procDeleteNetwork},
|
|
| 132 |
- {"/networks/" + nwID + "/endpoints/" + epID, nil, procDeleteEndpoint},
|
|
| 133 |
- {"/networks/" + nwID + "/endpoints/" + epID + "/sandboxes/" + sbID, nil, procLeaveEndpoint},
|
|
| 134 |
- {"/services/" + epID, nil, procUnpublishService},
|
|
| 135 |
- {"/services/" + epID + "/backend/" + sbID, nil, procDetachBackend},
|
|
| 136 |
- {"/sandboxes/" + sbID, nil, procDeleteSandbox},
|
|
| 137 |
- }, |
|
| 138 |
- } |
|
| 139 |
- |
|
| 140 |
- h.r = mux.NewRouter() |
|
| 141 |
- for method, routes := range m {
|
|
| 142 |
- for _, route := range routes {
|
|
| 143 |
- r := h.r.Path("/{.*}" + route.url).Methods(method).HandlerFunc(makeHandler(h.c, route.fct))
|
|
| 144 |
- if route.qrs != nil {
|
|
| 145 |
- r.Queries(route.qrs...) |
|
| 146 |
- } |
|
| 147 |
- |
|
| 148 |
- r = h.r.Path(route.url).Methods(method).HandlerFunc(makeHandler(h.c, route.fct)) |
|
| 149 |
- if route.qrs != nil {
|
|
| 150 |
- r.Queries(route.qrs...) |
|
| 151 |
- } |
|
| 152 |
- } |
|
| 153 |
- } |
|
| 154 |
-} |
|
| 155 |
- |
|
| 156 |
-func makeHandler(ctrl libnetwork.NetworkController, fct processor) http.HandlerFunc {
|
|
| 157 |
- return func(w http.ResponseWriter, req *http.Request) {
|
|
| 158 |
- var ( |
|
| 159 |
- body []byte |
|
| 160 |
- err error |
|
| 161 |
- ) |
|
| 162 |
- if req.Body != nil {
|
|
| 163 |
- body, err = ioutil.ReadAll(req.Body) |
|
| 164 |
- if err != nil {
|
|
| 165 |
- http.Error(w, "Invalid body: "+err.Error(), http.StatusBadRequest) |
|
| 166 |
- return |
|
| 167 |
- } |
|
| 168 |
- } |
|
| 169 |
- |
|
| 170 |
- res, rsp := fct(ctrl, mux.Vars(req), body) |
|
| 171 |
- if !rsp.isOK() {
|
|
| 172 |
- http.Error(w, rsp.Status, rsp.StatusCode) |
|
| 173 |
- return |
|
| 174 |
- } |
|
| 175 |
- if res != nil {
|
|
| 176 |
- writeJSON(w, rsp.StatusCode, res) |
|
| 177 |
- } |
|
| 178 |
- } |
|
| 179 |
-} |
|
| 180 |
- |
|
| 181 |
-/***************** |
|
| 182 |
- Resource Builders |
|
| 183 |
-******************/ |
|
| 184 |
- |
|
| 185 |
-func buildNetworkResource(nw libnetwork.Network) *networkResource {
|
|
| 186 |
- r := &networkResource{}
|
|
| 187 |
- if nw != nil {
|
|
| 188 |
- r.Name = nw.Name() |
|
| 189 |
- r.ID = nw.ID() |
|
| 190 |
- r.Type = nw.Type() |
|
| 191 |
- epl := nw.Endpoints() |
|
| 192 |
- r.Endpoints = make([]*endpointResource, 0, len(epl)) |
|
| 193 |
- for _, e := range epl {
|
|
| 194 |
- epr := buildEndpointResource(e) |
|
| 195 |
- r.Endpoints = append(r.Endpoints, epr) |
|
| 196 |
- } |
|
| 197 |
- } |
|
| 198 |
- return r |
|
| 199 |
-} |
|
| 200 |
- |
|
| 201 |
-func buildEndpointResource(ep libnetwork.Endpoint) *endpointResource {
|
|
| 202 |
- r := &endpointResource{}
|
|
| 203 |
- if ep != nil {
|
|
| 204 |
- r.Name = ep.Name() |
|
| 205 |
- r.ID = ep.ID() |
|
| 206 |
- r.Network = ep.Network() |
|
| 207 |
- } |
|
| 208 |
- return r |
|
| 209 |
-} |
|
| 210 |
- |
|
| 211 |
-func buildSandboxResource(sb libnetwork.Sandbox) *sandboxResource {
|
|
| 212 |
- r := &sandboxResource{}
|
|
| 213 |
- if sb != nil {
|
|
| 214 |
- r.ID = sb.ID() |
|
| 215 |
- r.Key = sb.Key() |
|
| 216 |
- r.ContainerID = sb.ContainerID() |
|
| 217 |
- } |
|
| 218 |
- return r |
|
| 219 |
-} |
|
| 220 |
- |
|
| 221 |
-/**************** |
|
| 222 |
- Options Parsers |
|
| 223 |
-*****************/ |
|
| 224 |
- |
|
| 225 |
-func (nc *networkCreate) parseOptions() []libnetwork.NetworkOption {
|
|
| 226 |
- var setFctList []libnetwork.NetworkOption |
|
| 227 |
- |
|
| 228 |
- if nc.Options != nil {
|
|
| 229 |
- setFctList = append(setFctList, libnetwork.NetworkOptionGeneric(nc.Options)) |
|
| 230 |
- } |
|
| 231 |
- |
|
| 232 |
- return setFctList |
|
| 233 |
-} |
|
| 234 |
- |
|
| 235 |
-func (sc *sandboxCreate) parseOptions() []libnetwork.SandboxOption {
|
|
| 236 |
- var setFctList []libnetwork.SandboxOption |
|
| 237 |
- if sc.HostName != "" {
|
|
| 238 |
- setFctList = append(setFctList, libnetwork.OptionHostname(sc.HostName)) |
|
| 239 |
- } |
|
| 240 |
- if sc.DomainName != "" {
|
|
| 241 |
- setFctList = append(setFctList, libnetwork.OptionDomainname(sc.DomainName)) |
|
| 242 |
- } |
|
| 243 |
- if sc.HostsPath != "" {
|
|
| 244 |
- setFctList = append(setFctList, libnetwork.OptionHostsPath(sc.HostsPath)) |
|
| 245 |
- } |
|
| 246 |
- if sc.ResolvConfPath != "" {
|
|
| 247 |
- setFctList = append(setFctList, libnetwork.OptionResolvConfPath(sc.ResolvConfPath)) |
|
| 248 |
- } |
|
| 249 |
- if sc.UseDefaultSandbox {
|
|
| 250 |
- setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox()) |
|
| 251 |
- } |
|
| 252 |
- if sc.UseExternalKey {
|
|
| 253 |
- setFctList = append(setFctList, libnetwork.OptionUseExternalKey()) |
|
| 254 |
- } |
|
| 255 |
- if sc.DNS != nil {
|
|
| 256 |
- for _, d := range sc.DNS {
|
|
| 257 |
- setFctList = append(setFctList, libnetwork.OptionDNS(d)) |
|
| 258 |
- } |
|
| 259 |
- } |
|
| 260 |
- if sc.ExtraHosts != nil {
|
|
| 261 |
- for _, e := range sc.ExtraHosts {
|
|
| 262 |
- setFctList = append(setFctList, libnetwork.OptionExtraHost(e.Name, e.Address)) |
|
| 263 |
- } |
|
| 264 |
- } |
|
| 265 |
- return setFctList |
|
| 266 |
-} |
|
| 267 |
- |
|
| 268 |
-func (ej *endpointJoin) parseOptions() []libnetwork.EndpointOption {
|
|
| 269 |
- // priority will go here |
|
| 270 |
- return []libnetwork.EndpointOption{}
|
|
| 271 |
-} |
|
| 272 |
- |
|
| 273 |
-/****************** |
|
| 274 |
- Process functions |
|
| 275 |
-*******************/ |
|
| 276 |
- |
|
| 277 |
-func processCreateDefaults(c libnetwork.NetworkController, nc *networkCreate) {
|
|
| 278 |
- if nc.NetworkType == "" {
|
|
| 279 |
- nc.NetworkType = c.Config().Daemon.DefaultDriver |
|
| 280 |
- } |
|
| 281 |
- if nc.NetworkType == BridgeNetworkDriver {
|
|
| 282 |
- if nc.Options == nil {
|
|
| 283 |
- nc.Options = make(map[string]interface{})
|
|
| 284 |
- } |
|
| 285 |
- genericData, ok := nc.Options[netlabel.GenericData] |
|
| 286 |
- if !ok {
|
|
| 287 |
- genericData = make(map[string]interface{})
|
|
| 288 |
- } |
|
| 289 |
- gData := genericData.(map[string]interface{})
|
|
| 290 |
- |
|
| 291 |
- if _, ok := gData["BridgeName"]; !ok {
|
|
| 292 |
- gData["BridgeName"] = nc.Name |
|
| 293 |
- } |
|
| 294 |
- nc.Options[netlabel.GenericData] = genericData |
|
| 295 |
- } |
|
| 296 |
-} |
|
| 297 |
- |
|
| 298 |
-/*************************** |
|
| 299 |
- NetworkController interface |
|
| 300 |
-****************************/ |
|
| 301 |
-func procCreateNetwork(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 302 |
- var create networkCreate |
|
| 303 |
- |
|
| 304 |
- err := json.Unmarshal(body, &create) |
|
| 305 |
- if err != nil {
|
|
| 306 |
- return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
|
|
| 307 |
- } |
|
| 308 |
- processCreateDefaults(c, &create) |
|
| 309 |
- |
|
| 310 |
- nw, err := c.NewNetwork(create.NetworkType, create.Name, create.parseOptions()...) |
|
| 311 |
- if err != nil {
|
|
| 312 |
- return "", convertNetworkError(err) |
|
| 313 |
- } |
|
| 314 |
- |
|
| 315 |
- return nw.ID(), &createdResponse |
|
| 316 |
-} |
|
| 317 |
- |
|
| 318 |
-func procGetNetwork(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 319 |
- t, by := detectNetworkTarget(vars) |
|
| 320 |
- nw, errRsp := findNetwork(c, t, by) |
|
| 321 |
- if !errRsp.isOK() {
|
|
| 322 |
- return nil, errRsp |
|
| 323 |
- } |
|
| 324 |
- return buildNetworkResource(nw), &successResponse |
|
| 325 |
-} |
|
| 326 |
- |
|
| 327 |
-func procGetNetworks(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 328 |
- var list []*networkResource |
|
| 329 |
- |
|
| 330 |
- // Look for query filters and validate |
|
| 331 |
- name, queryByName := vars[urlNwName] |
|
| 332 |
- shortID, queryByPid := vars[urlNwPID] |
|
| 333 |
- if queryByName && queryByPid {
|
|
| 334 |
- return nil, &badQueryResponse |
|
| 335 |
- } |
|
| 336 |
- |
|
| 337 |
- if queryByName {
|
|
| 338 |
- if nw, errRsp := findNetwork(c, name, byName); errRsp.isOK() {
|
|
| 339 |
- list = append(list, buildNetworkResource(nw)) |
|
| 340 |
- } |
|
| 341 |
- } else if queryByPid {
|
|
| 342 |
- // Return all the prefix-matching networks |
|
| 343 |
- l := func(nw libnetwork.Network) bool {
|
|
| 344 |
- if strings.HasPrefix(nw.ID(), shortID) {
|
|
| 345 |
- list = append(list, buildNetworkResource(nw)) |
|
| 346 |
- } |
|
| 347 |
- return false |
|
| 348 |
- } |
|
| 349 |
- c.WalkNetworks(l) |
|
| 350 |
- } else {
|
|
| 351 |
- for _, nw := range c.Networks() {
|
|
| 352 |
- list = append(list, buildNetworkResource(nw)) |
|
| 353 |
- } |
|
| 354 |
- } |
|
| 355 |
- |
|
| 356 |
- return list, &successResponse |
|
| 357 |
-} |
|
| 358 |
- |
|
| 359 |
-func procCreateSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 360 |
- var create sandboxCreate |
|
| 361 |
- |
|
| 362 |
- err := json.Unmarshal(body, &create) |
|
| 363 |
- if err != nil {
|
|
| 364 |
- return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
|
|
| 365 |
- } |
|
| 366 |
- |
|
| 367 |
- sb, err := c.NewSandbox(create.ContainerID, create.parseOptions()...) |
|
| 368 |
- if err != nil {
|
|
| 369 |
- return "", convertNetworkError(err) |
|
| 370 |
- } |
|
| 371 |
- |
|
| 372 |
- return sb.ID(), &createdResponse |
|
| 373 |
-} |
|
| 374 |
- |
|
| 375 |
-/****************** |
|
| 376 |
- Network interface |
|
| 377 |
-*******************/ |
|
| 378 |
-func procCreateEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 379 |
- var ec endpointCreate |
|
| 380 |
- |
|
| 381 |
- err := json.Unmarshal(body, &ec) |
|
| 382 |
- if err != nil {
|
|
| 383 |
- return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
|
|
| 384 |
- } |
|
| 385 |
- |
|
| 386 |
- nwT, nwBy := detectNetworkTarget(vars) |
|
| 387 |
- n, errRsp := findNetwork(c, nwT, nwBy) |
|
| 388 |
- if !errRsp.isOK() {
|
|
| 389 |
- return "", errRsp |
|
| 390 |
- } |
|
| 391 |
- |
|
| 392 |
- var setFctList []libnetwork.EndpointOption |
|
| 393 |
- if ec.ExposedPorts != nil {
|
|
| 394 |
- setFctList = append(setFctList, libnetwork.CreateOptionExposedPorts(ec.ExposedPorts)) |
|
| 395 |
- } |
|
| 396 |
- if ec.PortMapping != nil {
|
|
| 397 |
- setFctList = append(setFctList, libnetwork.CreateOptionPortMapping(ec.PortMapping)) |
|
| 398 |
- } |
|
| 399 |
- |
|
| 400 |
- ep, err := n.CreateEndpoint(ec.Name, setFctList...) |
|
| 401 |
- if err != nil {
|
|
| 402 |
- return "", convertNetworkError(err) |
|
| 403 |
- } |
|
| 404 |
- |
|
| 405 |
- return ep.ID(), &createdResponse |
|
| 406 |
-} |
|
| 407 |
- |
|
| 408 |
-func procGetEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 409 |
- nwT, nwBy := detectNetworkTarget(vars) |
|
| 410 |
- epT, epBy := detectEndpointTarget(vars) |
|
| 411 |
- |
|
| 412 |
- ep, errRsp := findEndpoint(c, nwT, epT, nwBy, epBy) |
|
| 413 |
- if !errRsp.isOK() {
|
|
| 414 |
- return nil, errRsp |
|
| 415 |
- } |
|
| 416 |
- |
|
| 417 |
- return buildEndpointResource(ep), &successResponse |
|
| 418 |
-} |
|
| 419 |
- |
|
| 420 |
-func procGetEndpoints(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 421 |
- // Look for query filters and validate |
|
| 422 |
- name, queryByName := vars[urlEpName] |
|
| 423 |
- shortID, queryByPid := vars[urlEpPID] |
|
| 424 |
- if queryByName && queryByPid {
|
|
| 425 |
- return nil, &badQueryResponse |
|
| 426 |
- } |
|
| 427 |
- |
|
| 428 |
- nwT, nwBy := detectNetworkTarget(vars) |
|
| 429 |
- nw, errRsp := findNetwork(c, nwT, nwBy) |
|
| 430 |
- if !errRsp.isOK() {
|
|
| 431 |
- return nil, errRsp |
|
| 432 |
- } |
|
| 433 |
- |
|
| 434 |
- var list []*endpointResource |
|
| 435 |
- |
|
| 436 |
- // If query parameter is specified, return a filtered collection |
|
| 437 |
- if queryByName {
|
|
| 438 |
- if ep, errRsp := findEndpoint(c, nwT, name, nwBy, byName); errRsp.isOK() {
|
|
| 439 |
- list = append(list, buildEndpointResource(ep)) |
|
| 440 |
- } |
|
| 441 |
- } else if queryByPid {
|
|
| 442 |
- // Return all the prefix-matching endpoints |
|
| 443 |
- l := func(ep libnetwork.Endpoint) bool {
|
|
| 444 |
- if strings.HasPrefix(ep.ID(), shortID) {
|
|
| 445 |
- list = append(list, buildEndpointResource(ep)) |
|
| 446 |
- } |
|
| 447 |
- return false |
|
| 448 |
- } |
|
| 449 |
- nw.WalkEndpoints(l) |
|
| 450 |
- } else {
|
|
| 451 |
- for _, ep := range nw.Endpoints() {
|
|
| 452 |
- epr := buildEndpointResource(ep) |
|
| 453 |
- list = append(list, epr) |
|
| 454 |
- } |
|
| 455 |
- } |
|
| 456 |
- |
|
| 457 |
- return list, &successResponse |
|
| 458 |
-} |
|
| 459 |
- |
|
| 460 |
-func procDeleteNetwork(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 461 |
- target, by := detectNetworkTarget(vars) |
|
| 462 |
- |
|
| 463 |
- nw, errRsp := findNetwork(c, target, by) |
|
| 464 |
- if !errRsp.isOK() {
|
|
| 465 |
- return nil, errRsp |
|
| 466 |
- } |
|
| 467 |
- |
|
| 468 |
- err := nw.Delete() |
|
| 469 |
- if err != nil {
|
|
| 470 |
- return nil, convertNetworkError(err) |
|
| 471 |
- } |
|
| 472 |
- |
|
| 473 |
- return nil, &successResponse |
|
| 474 |
-} |
|
| 475 |
- |
|
| 476 |
-/****************** |
|
| 477 |
- Endpoint interface |
|
| 478 |
-*******************/ |
|
| 479 |
-func procJoinEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 480 |
- var ej endpointJoin |
|
| 481 |
- err := json.Unmarshal(body, &ej) |
|
| 482 |
- if err != nil {
|
|
| 483 |
- return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
|
|
| 484 |
- } |
|
| 485 |
- |
|
| 486 |
- nwT, nwBy := detectNetworkTarget(vars) |
|
| 487 |
- epT, epBy := detectEndpointTarget(vars) |
|
| 488 |
- |
|
| 489 |
- ep, errRsp := findEndpoint(c, nwT, epT, nwBy, epBy) |
|
| 490 |
- if !errRsp.isOK() {
|
|
| 491 |
- return nil, errRsp |
|
| 492 |
- } |
|
| 493 |
- |
|
| 494 |
- sb, errRsp := findSandbox(c, ej.SandboxID, byID) |
|
| 495 |
- if !errRsp.isOK() {
|
|
| 496 |
- return nil, errRsp |
|
| 497 |
- } |
|
| 498 |
- |
|
| 499 |
- err = ep.Join(sb) |
|
| 500 |
- if err != nil {
|
|
| 501 |
- return nil, convertNetworkError(err) |
|
| 502 |
- } |
|
| 503 |
- return sb.Key(), &successResponse |
|
| 504 |
-} |
|
| 505 |
- |
|
| 506 |
-func procLeaveEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 507 |
- nwT, nwBy := detectNetworkTarget(vars) |
|
| 508 |
- epT, epBy := detectEndpointTarget(vars) |
|
| 509 |
- |
|
| 510 |
- ep, errRsp := findEndpoint(c, nwT, epT, nwBy, epBy) |
|
| 511 |
- if !errRsp.isOK() {
|
|
| 512 |
- return nil, errRsp |
|
| 513 |
- } |
|
| 514 |
- |
|
| 515 |
- sb, errRsp := findSandbox(c, vars[urlSbID], byID) |
|
| 516 |
- if !errRsp.isOK() {
|
|
| 517 |
- return nil, errRsp |
|
| 518 |
- } |
|
| 519 |
- |
|
| 520 |
- err := ep.Leave(sb) |
|
| 521 |
- if err != nil {
|
|
| 522 |
- return nil, convertNetworkError(err) |
|
| 523 |
- } |
|
| 524 |
- |
|
| 525 |
- return nil, &successResponse |
|
| 526 |
-} |
|
| 527 |
- |
|
| 528 |
-func procDeleteEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 529 |
- nwT, nwBy := detectNetworkTarget(vars) |
|
| 530 |
- epT, epBy := detectEndpointTarget(vars) |
|
| 531 |
- |
|
| 532 |
- ep, errRsp := findEndpoint(c, nwT, epT, nwBy, epBy) |
|
| 533 |
- if !errRsp.isOK() {
|
|
| 534 |
- return nil, errRsp |
|
| 535 |
- } |
|
| 536 |
- |
|
| 537 |
- err := ep.Delete() |
|
| 538 |
- if err != nil {
|
|
| 539 |
- return nil, convertNetworkError(err) |
|
| 540 |
- } |
|
| 541 |
- |
|
| 542 |
- return nil, &successResponse |
|
| 543 |
-} |
|
| 544 |
- |
|
| 545 |
-/****************** |
|
| 546 |
- Service interface |
|
| 547 |
-*******************/ |
|
| 548 |
-func procGetServices(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 549 |
- // Look for query filters and validate |
|
| 550 |
- nwName, filterByNwName := vars[urlNwName] |
|
| 551 |
- svName, queryBySvName := vars[urlEpName] |
|
| 552 |
- shortID, queryBySvPID := vars[urlEpPID] |
|
| 553 |
- |
|
| 554 |
- if filterByNwName && queryBySvName || filterByNwName && queryBySvPID || queryBySvName && queryBySvPID {
|
|
| 555 |
- return nil, &badQueryResponse |
|
| 556 |
- } |
|
| 557 |
- |
|
| 558 |
- var list []*endpointResource |
|
| 559 |
- |
|
| 560 |
- switch {
|
|
| 561 |
- case filterByNwName: |
|
| 562 |
- // return all service present on the specified network |
|
| 563 |
- nw, errRsp := findNetwork(c, nwName, byName) |
|
| 564 |
- if !errRsp.isOK() {
|
|
| 565 |
- return list, &successResponse |
|
| 566 |
- } |
|
| 567 |
- for _, ep := range nw.Endpoints() {
|
|
| 568 |
- epr := buildEndpointResource(ep) |
|
| 569 |
- list = append(list, epr) |
|
| 570 |
- } |
|
| 571 |
- case queryBySvName: |
|
| 572 |
- // Look in each network for the service with the specified name |
|
| 573 |
- l := func(ep libnetwork.Endpoint) bool {
|
|
| 574 |
- if ep.Name() == svName {
|
|
| 575 |
- list = append(list, buildEndpointResource(ep)) |
|
| 576 |
- return true |
|
| 577 |
- } |
|
| 578 |
- return false |
|
| 579 |
- } |
|
| 580 |
- for _, nw := range c.Networks() {
|
|
| 581 |
- nw.WalkEndpoints(l) |
|
| 582 |
- } |
|
| 583 |
- case queryBySvPID: |
|
| 584 |
- // Return all the prefix-matching services |
|
| 585 |
- l := func(ep libnetwork.Endpoint) bool {
|
|
| 586 |
- if strings.HasPrefix(ep.ID(), shortID) {
|
|
| 587 |
- list = append(list, buildEndpointResource(ep)) |
|
| 588 |
- } |
|
| 589 |
- return false |
|
| 590 |
- } |
|
| 591 |
- for _, nw := range c.Networks() {
|
|
| 592 |
- nw.WalkEndpoints(l) |
|
| 593 |
- } |
|
| 594 |
- default: |
|
| 595 |
- for _, nw := range c.Networks() {
|
|
| 596 |
- for _, ep := range nw.Endpoints() {
|
|
| 597 |
- epr := buildEndpointResource(ep) |
|
| 598 |
- list = append(list, epr) |
|
| 599 |
- } |
|
| 600 |
- } |
|
| 601 |
- } |
|
| 602 |
- |
|
| 603 |
- return list, &successResponse |
|
| 604 |
-} |
|
| 605 |
- |
|
| 606 |
-func procGetService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 607 |
- epT, epBy := detectEndpointTarget(vars) |
|
| 608 |
- sv, errRsp := findService(c, epT, epBy) |
|
| 609 |
- if !errRsp.isOK() {
|
|
| 610 |
- return nil, endpointToService(errRsp) |
|
| 611 |
- } |
|
| 612 |
- return buildEndpointResource(sv), &successResponse |
|
| 613 |
-} |
|
| 614 |
- |
|
| 615 |
-func procPublishService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 616 |
- var sp servicePublish |
|
| 617 |
- |
|
| 618 |
- err := json.Unmarshal(body, &sp) |
|
| 619 |
- if err != nil {
|
|
| 620 |
- return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
|
|
| 621 |
- } |
|
| 622 |
- |
|
| 623 |
- n, errRsp := findNetwork(c, sp.Network, byName) |
|
| 624 |
- if !errRsp.isOK() {
|
|
| 625 |
- return "", errRsp |
|
| 626 |
- } |
|
| 627 |
- |
|
| 628 |
- var setFctList []libnetwork.EndpointOption |
|
| 629 |
- if sp.ExposedPorts != nil {
|
|
| 630 |
- setFctList = append(setFctList, libnetwork.CreateOptionExposedPorts(sp.ExposedPorts)) |
|
| 631 |
- } |
|
| 632 |
- if sp.PortMapping != nil {
|
|
| 633 |
- setFctList = append(setFctList, libnetwork.CreateOptionPortMapping(sp.PortMapping)) |
|
| 634 |
- } |
|
| 635 |
- |
|
| 636 |
- ep, err := n.CreateEndpoint(sp.Name, setFctList...) |
|
| 637 |
- if err != nil {
|
|
| 638 |
- return "", endpointToService(convertNetworkError(err)) |
|
| 639 |
- } |
|
| 640 |
- |
|
| 641 |
- return ep.ID(), &createdResponse |
|
| 642 |
-} |
|
| 643 |
- |
|
| 644 |
-func procUnpublishService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 645 |
- epT, epBy := detectEndpointTarget(vars) |
|
| 646 |
- sv, errRsp := findService(c, epT, epBy) |
|
| 647 |
- if !errRsp.isOK() {
|
|
| 648 |
- return nil, errRsp |
|
| 649 |
- } |
|
| 650 |
- err := sv.Delete() |
|
| 651 |
- if err != nil {
|
|
| 652 |
- return nil, endpointToService(convertNetworkError(err)) |
|
| 653 |
- } |
|
| 654 |
- return nil, &successResponse |
|
| 655 |
-} |
|
| 656 |
- |
|
| 657 |
-func procAttachBackend(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 658 |
- var bk endpointJoin |
|
| 659 |
- err := json.Unmarshal(body, &bk) |
|
| 660 |
- if err != nil {
|
|
| 661 |
- return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
|
|
| 662 |
- } |
|
| 663 |
- |
|
| 664 |
- epT, epBy := detectEndpointTarget(vars) |
|
| 665 |
- sv, errRsp := findService(c, epT, epBy) |
|
| 666 |
- if !errRsp.isOK() {
|
|
| 667 |
- return nil, errRsp |
|
| 668 |
- } |
|
| 669 |
- |
|
| 670 |
- sb, errRsp := findSandbox(c, bk.SandboxID, byID) |
|
| 671 |
- if !errRsp.isOK() {
|
|
| 672 |
- return nil, errRsp |
|
| 673 |
- } |
|
| 674 |
- |
|
| 675 |
- err = sv.Join(sb) |
|
| 676 |
- if err != nil {
|
|
| 677 |
- return nil, convertNetworkError(err) |
|
| 678 |
- } |
|
| 679 |
- return sb.Key(), &successResponse |
|
| 680 |
-} |
|
| 681 |
- |
|
| 682 |
-func procDetachBackend(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 683 |
- epT, epBy := detectEndpointTarget(vars) |
|
| 684 |
- sv, errRsp := findService(c, epT, epBy) |
|
| 685 |
- if !errRsp.isOK() {
|
|
| 686 |
- return nil, errRsp |
|
| 687 |
- } |
|
| 688 |
- |
|
| 689 |
- sb, errRsp := findSandbox(c, vars[urlSbID], byID) |
|
| 690 |
- if !errRsp.isOK() {
|
|
| 691 |
- return nil, errRsp |
|
| 692 |
- } |
|
| 693 |
- |
|
| 694 |
- err := sv.Leave(sb) |
|
| 695 |
- if err != nil {
|
|
| 696 |
- return nil, convertNetworkError(err) |
|
| 697 |
- } |
|
| 698 |
- |
|
| 699 |
- return nil, &successResponse |
|
| 700 |
-} |
|
| 701 |
- |
|
| 702 |
-/****************** |
|
| 703 |
- Sandbox interface |
|
| 704 |
-*******************/ |
|
| 705 |
-func procGetSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 706 |
- if epT, ok := vars[urlEpID]; ok {
|
|
| 707 |
- sv, errRsp := findService(c, epT, byID) |
|
| 708 |
- if !errRsp.isOK() {
|
|
| 709 |
- return nil, endpointToService(errRsp) |
|
| 710 |
- } |
|
| 711 |
- return buildSandboxResource(sv.Info().Sandbox()), &successResponse |
|
| 712 |
- } |
|
| 713 |
- |
|
| 714 |
- sbT, by := detectSandboxTarget(vars) |
|
| 715 |
- sb, errRsp := findSandbox(c, sbT, by) |
|
| 716 |
- if !errRsp.isOK() {
|
|
| 717 |
- return nil, errRsp |
|
| 718 |
- } |
|
| 719 |
- return buildSandboxResource(sb), &successResponse |
|
| 720 |
-} |
|
| 721 |
- |
|
| 722 |
-type cndFnMkr func(string) cndFn |
|
| 723 |
-type cndFn func(libnetwork.Sandbox) bool |
|
| 724 |
- |
|
| 725 |
-// list of (query type, condition function makers) couples |
|
| 726 |
-var cndMkrList = []struct {
|
|
| 727 |
- identifier string |
|
| 728 |
- maker cndFnMkr |
|
| 729 |
-}{
|
|
| 730 |
- {urlSbPID, func(id string) cndFn {
|
|
| 731 |
- return func(sb libnetwork.Sandbox) bool { return strings.HasPrefix(sb.ID(), id) }
|
|
| 732 |
- }}, |
|
| 733 |
- {urlCnID, func(id string) cndFn {
|
|
| 734 |
- return func(sb libnetwork.Sandbox) bool { return sb.ContainerID() == id }
|
|
| 735 |
- }}, |
|
| 736 |
- {urlCnPID, func(id string) cndFn {
|
|
| 737 |
- return func(sb libnetwork.Sandbox) bool { return strings.HasPrefix(sb.ContainerID(), id) }
|
|
| 738 |
- }}, |
|
| 739 |
-} |
|
| 740 |
- |
|
| 741 |
-func getQueryCondition(vars map[string]string) func(libnetwork.Sandbox) bool {
|
|
| 742 |
- for _, im := range cndMkrList {
|
|
| 743 |
- if val, ok := vars[im.identifier]; ok {
|
|
| 744 |
- return im.maker(val) |
|
| 745 |
- } |
|
| 746 |
- } |
|
| 747 |
- return func(sb libnetwork.Sandbox) bool { return true }
|
|
| 748 |
-} |
|
| 749 |
- |
|
| 750 |
-func sandboxWalker(condition cndFn, list *[]*sandboxResource) libnetwork.SandboxWalker {
|
|
| 751 |
- return func(sb libnetwork.Sandbox) bool {
|
|
| 752 |
- if condition(sb) {
|
|
| 753 |
- *list = append(*list, buildSandboxResource(sb)) |
|
| 754 |
- } |
|
| 755 |
- return false |
|
| 756 |
- } |
|
| 757 |
-} |
|
| 758 |
- |
|
| 759 |
-func procGetSandboxes(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 760 |
- var list []*sandboxResource |
|
| 761 |
- |
|
| 762 |
- cnd := getQueryCondition(vars) |
|
| 763 |
- c.WalkSandboxes(sandboxWalker(cnd, &list)) |
|
| 764 |
- |
|
| 765 |
- return list, &successResponse |
|
| 766 |
-} |
|
| 767 |
- |
|
| 768 |
-func procDeleteSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
|
| 769 |
- sbT, by := detectSandboxTarget(vars) |
|
| 770 |
- |
|
| 771 |
- sb, errRsp := findSandbox(c, sbT, by) |
|
| 772 |
- if !errRsp.isOK() {
|
|
| 773 |
- return nil, errRsp |
|
| 774 |
- } |
|
| 775 |
- |
|
| 776 |
- err := sb.Delete() |
|
| 777 |
- if err != nil {
|
|
| 778 |
- return nil, convertNetworkError(err) |
|
| 779 |
- } |
|
| 780 |
- |
|
| 781 |
- return nil, &successResponse |
|
| 782 |
-} |
|
| 783 |
- |
|
| 784 |
-/*********** |
|
| 785 |
- Utilities |
|
| 786 |
-************/ |
|
| 787 |
-const ( |
|
| 788 |
- byID = iota |
|
| 789 |
- byName |
|
| 790 |
-) |
|
| 791 |
- |
|
| 792 |
-func detectNetworkTarget(vars map[string]string) (string, int) {
|
|
| 793 |
- if target, ok := vars[urlNwName]; ok {
|
|
| 794 |
- return target, byName |
|
| 795 |
- } |
|
| 796 |
- if target, ok := vars[urlNwID]; ok {
|
|
| 797 |
- return target, byID |
|
| 798 |
- } |
|
| 799 |
- // vars are populated from the URL, following cannot happen |
|
| 800 |
- panic("Missing URL variable parameter for network")
|
|
| 801 |
-} |
|
| 802 |
- |
|
| 803 |
-func detectSandboxTarget(vars map[string]string) (string, int) {
|
|
| 804 |
- if target, ok := vars[urlSbID]; ok {
|
|
| 805 |
- return target, byID |
|
| 806 |
- } |
|
| 807 |
- // vars are populated from the URL, following cannot happen |
|
| 808 |
- panic("Missing URL variable parameter for sandbox")
|
|
| 809 |
-} |
|
| 810 |
- |
|
| 811 |
-func detectEndpointTarget(vars map[string]string) (string, int) {
|
|
| 812 |
- if target, ok := vars[urlEpName]; ok {
|
|
| 813 |
- return target, byName |
|
| 814 |
- } |
|
| 815 |
- if target, ok := vars[urlEpID]; ok {
|
|
| 816 |
- return target, byID |
|
| 817 |
- } |
|
| 818 |
- // vars are populated from the URL, following cannot happen |
|
| 819 |
- panic("Missing URL variable parameter for endpoint")
|
|
| 820 |
-} |
|
| 821 |
- |
|
| 822 |
-func findNetwork(c libnetwork.NetworkController, s string, by int) (libnetwork.Network, *responseStatus) {
|
|
| 823 |
- var ( |
|
| 824 |
- nw libnetwork.Network |
|
| 825 |
- err error |
|
| 826 |
- ) |
|
| 827 |
- switch by {
|
|
| 828 |
- case byID: |
|
| 829 |
- nw, err = c.NetworkByID(s) |
|
| 830 |
- case byName: |
|
| 831 |
- if s == "" {
|
|
| 832 |
- s = c.Config().Daemon.DefaultNetwork |
|
| 833 |
- } |
|
| 834 |
- nw, err = c.NetworkByName(s) |
|
| 835 |
- default: |
|
| 836 |
- panic(fmt.Sprintf("unexpected selector for network search: %d", by))
|
|
| 837 |
- } |
|
| 838 |
- if err != nil {
|
|
| 839 |
- if _, ok := err.(types.NotFoundError); ok {
|
|
| 840 |
- return nil, &responseStatus{Status: "Resource not found: Network", StatusCode: http.StatusNotFound}
|
|
| 841 |
- } |
|
| 842 |
- return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
|
|
| 843 |
- } |
|
| 844 |
- return nw, &successResponse |
|
| 845 |
-} |
|
| 846 |
- |
|
| 847 |
-func findSandbox(c libnetwork.NetworkController, s string, by int) (libnetwork.Sandbox, *responseStatus) {
|
|
| 848 |
- var ( |
|
| 849 |
- sb libnetwork.Sandbox |
|
| 850 |
- err error |
|
| 851 |
- ) |
|
| 852 |
- |
|
| 853 |
- switch by {
|
|
| 854 |
- case byID: |
|
| 855 |
- sb, err = c.SandboxByID(s) |
|
| 856 |
- default: |
|
| 857 |
- panic(fmt.Sprintf("unexpected selector for sandbox search: %d", by))
|
|
| 858 |
- } |
|
| 859 |
- if err != nil {
|
|
| 860 |
- if _, ok := err.(types.NotFoundError); ok {
|
|
| 861 |
- return nil, &responseStatus{Status: "Resource not found: Sandbox", StatusCode: http.StatusNotFound}
|
|
| 862 |
- } |
|
| 863 |
- return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
|
|
| 864 |
- } |
|
| 865 |
- return sb, &successResponse |
|
| 866 |
-} |
|
| 867 |
- |
|
| 868 |
-func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int) (libnetwork.Endpoint, *responseStatus) {
|
|
| 869 |
- nw, errRsp := findNetwork(c, ns, nwBy) |
|
| 870 |
- if !errRsp.isOK() {
|
|
| 871 |
- return nil, errRsp |
|
| 872 |
- } |
|
| 873 |
- var ( |
|
| 874 |
- err error |
|
| 875 |
- ep libnetwork.Endpoint |
|
| 876 |
- ) |
|
| 877 |
- switch epBy {
|
|
| 878 |
- case byID: |
|
| 879 |
- ep, err = nw.EndpointByID(es) |
|
| 880 |
- case byName: |
|
| 881 |
- ep, err = nw.EndpointByName(es) |
|
| 882 |
- default: |
|
| 883 |
- panic(fmt.Sprintf("unexpected selector for endpoint search: %d", epBy))
|
|
| 884 |
- } |
|
| 885 |
- if err != nil {
|
|
| 886 |
- if _, ok := err.(types.NotFoundError); ok {
|
|
| 887 |
- return nil, &responseStatus{Status: "Resource not found: Endpoint", StatusCode: http.StatusNotFound}
|
|
| 888 |
- } |
|
| 889 |
- return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
|
|
| 890 |
- } |
|
| 891 |
- return ep, &successResponse |
|
| 892 |
-} |
|
| 893 |
- |
|
| 894 |
-func findService(c libnetwork.NetworkController, svs string, svBy int) (libnetwork.Endpoint, *responseStatus) {
|
|
| 895 |
- for _, nw := range c.Networks() {
|
|
| 896 |
- var ( |
|
| 897 |
- ep libnetwork.Endpoint |
|
| 898 |
- err error |
|
| 899 |
- ) |
|
| 900 |
- switch svBy {
|
|
| 901 |
- case byID: |
|
| 902 |
- ep, err = nw.EndpointByID(svs) |
|
| 903 |
- case byName: |
|
| 904 |
- ep, err = nw.EndpointByName(svs) |
|
| 905 |
- default: |
|
| 906 |
- panic(fmt.Sprintf("unexpected selector for service search: %d", svBy))
|
|
| 907 |
- } |
|
| 908 |
- if err == nil {
|
|
| 909 |
- return ep, &successResponse |
|
| 910 |
- } else if _, ok := err.(types.NotFoundError); !ok {
|
|
| 911 |
- return nil, convertNetworkError(err) |
|
| 912 |
- } |
|
| 913 |
- } |
|
| 914 |
- return nil, &responseStatus{Status: "Service not found", StatusCode: http.StatusNotFound}
|
|
| 915 |
-} |
|
| 916 |
- |
|
| 917 |
-func endpointToService(rsp *responseStatus) *responseStatus {
|
|
| 918 |
- rsp.Status = strings.Replace(rsp.Status, "endpoint", "service", -1) |
|
| 919 |
- return rsp |
|
| 920 |
-} |
|
| 921 |
- |
|
| 922 |
-func convertNetworkError(err error) *responseStatus {
|
|
| 923 |
- var code int |
|
| 924 |
- switch err.(type) {
|
|
| 925 |
- case types.BadRequestError: |
|
| 926 |
- code = http.StatusBadRequest |
|
| 927 |
- case types.ForbiddenError: |
|
| 928 |
- code = http.StatusForbidden |
|
| 929 |
- case types.NotFoundError: |
|
| 930 |
- code = http.StatusNotFound |
|
| 931 |
- case types.TimeoutError: |
|
| 932 |
- code = http.StatusRequestTimeout |
|
| 933 |
- case types.NotImplementedError: |
|
| 934 |
- code = http.StatusNotImplemented |
|
| 935 |
- case types.NoServiceError: |
|
| 936 |
- code = http.StatusServiceUnavailable |
|
| 937 |
- case types.InternalError: |
|
| 938 |
- code = http.StatusInternalServerError |
|
| 939 |
- default: |
|
| 940 |
- code = http.StatusInternalServerError |
|
| 941 |
- } |
|
| 942 |
- return &responseStatus{Status: err.Error(), StatusCode: code}
|
|
| 943 |
-} |
|
| 944 |
- |
|
| 945 |
-func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
|
|
| 946 |
- w.Header().Set("Content-Type", "application/json")
|
|
| 947 |
- w.WriteHeader(code) |
|
| 948 |
- return json.NewEncoder(w).Encode(v) |
|
| 949 |
-} |
| 950 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,80 +0,0 @@ |
| 1 |
-package api |
|
| 2 |
- |
|
| 3 |
-import "github.com/docker/libnetwork/types" |
|
| 4 |
- |
|
| 5 |
-/*********** |
|
| 6 |
- Resources |
|
| 7 |
-************/ |
|
| 8 |
- |
|
| 9 |
-// networkResource is the body of the "get network" http response message |
|
| 10 |
-type networkResource struct {
|
|
| 11 |
- Name string `json:"name"` |
|
| 12 |
- ID string `json:"id"` |
|
| 13 |
- Type string `json:"type"` |
|
| 14 |
- Endpoints []*endpointResource `json:"endpoints"` |
|
| 15 |
-} |
|
| 16 |
- |
|
| 17 |
-// endpointResource is the body of the "get endpoint" http response message |
|
| 18 |
-type endpointResource struct {
|
|
| 19 |
- Name string `json:"name"` |
|
| 20 |
- ID string `json:"id"` |
|
| 21 |
- Network string `json:"network"` |
|
| 22 |
-} |
|
| 23 |
- |
|
| 24 |
-// sandboxResource is the body of "get service backend" response message |
|
| 25 |
-type sandboxResource struct {
|
|
| 26 |
- ID string `json:"id"` |
|
| 27 |
- Key string `json:"key"` |
|
| 28 |
- ContainerID string `json:"container_id"` |
|
| 29 |
- // will add more fields once labels change is in |
|
| 30 |
-} |
|
| 31 |
- |
|
| 32 |
-/*********** |
|
| 33 |
- Body types |
|
| 34 |
- ************/ |
|
| 35 |
- |
|
| 36 |
-// networkCreate is the expected body of the "create network" http request message |
|
| 37 |
-type networkCreate struct {
|
|
| 38 |
- Name string `json:"name"` |
|
| 39 |
- NetworkType string `json:"network_type"` |
|
| 40 |
- Options map[string]interface{} `json:"options"`
|
|
| 41 |
-} |
|
| 42 |
- |
|
| 43 |
-// endpointCreate represents the body of the "create endpoint" http request message |
|
| 44 |
-type endpointCreate struct {
|
|
| 45 |
- Name string `json:"name"` |
|
| 46 |
- ExposedPorts []types.TransportPort `json:"exposed_ports"` |
|
| 47 |
- PortMapping []types.PortBinding `json:"port_mapping"` |
|
| 48 |
-} |
|
| 49 |
- |
|
| 50 |
-// sandboxCreate is the expected body of the "create sandbox" http request message |
|
| 51 |
-type sandboxCreate struct {
|
|
| 52 |
- ContainerID string `json:"container_id"` |
|
| 53 |
- HostName string `json:"host_name"` |
|
| 54 |
- DomainName string `json:"domain_name"` |
|
| 55 |
- HostsPath string `json:"hosts_path"` |
|
| 56 |
- ResolvConfPath string `json:"resolv_conf_path"` |
|
| 57 |
- DNS []string `json:"dns"` |
|
| 58 |
- ExtraHosts []extraHost `json:"extra_hosts"` |
|
| 59 |
- UseDefaultSandbox bool `json:"use_default_sandbox"` |
|
| 60 |
- UseExternalKey bool `json:"use_external_key"` |
|
| 61 |
-} |
|
| 62 |
- |
|
| 63 |
-// endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages |
|
| 64 |
-type endpointJoin struct {
|
|
| 65 |
- SandboxID string `json:"sandbox_id"` |
|
| 66 |
-} |
|
| 67 |
- |
|
| 68 |
-// servicePublish represents the body of the "publish service" http request message |
|
| 69 |
-type servicePublish struct {
|
|
| 70 |
- Name string `json:"name"` |
|
| 71 |
- Network string `json:"network_name"` |
|
| 72 |
- ExposedPorts []types.TransportPort `json:"exposed_ports"` |
|
| 73 |
- PortMapping []types.PortBinding `json:"port_mapping"` |
|
| 74 |
-} |
|
| 75 |
- |
|
| 76 |
-// extraHost represents the extra host object |
|
| 77 |
-type extraHost struct {
|
|
| 78 |
- Name string `json:"name"` |
|
| 79 |
- Address string `json:"address"` |
|
| 80 |
-} |