dnet.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "net/http"
  9. "net/http/httptest"
  10. "os"
  11. "strings"
  12. "github.com/codegangsta/cli"
  13. "github.com/docker/docker/pkg/parsers"
  14. "github.com/docker/docker/pkg/reexec"
  15. "github.com/Sirupsen/logrus"
  16. "github.com/docker/docker/pkg/term"
  17. "github.com/docker/libnetwork"
  18. "github.com/docker/libnetwork/api"
  19. "github.com/docker/libnetwork/config"
  20. "github.com/docker/libnetwork/driverapi"
  21. "github.com/docker/libnetwork/netlabel"
  22. "github.com/docker/libnetwork/options"
  23. "github.com/gorilla/mux"
  24. )
  25. const (
  26. // DefaultHTTPHost is used if only port is provided to -H flag e.g. docker -d -H tcp://:8080
  27. DefaultHTTPHost = "0.0.0.0"
  28. // DefaultHTTPPort is the default http port used by dnet
  29. DefaultHTTPPort = 2385
  30. // DefaultUnixSocket exported
  31. DefaultUnixSocket = "/var/run/dnet.sock"
  32. cfgFileEnv = "LIBNETWORK_CFG"
  33. defaultCfgFile = "/etc/default/libnetwork.toml"
  34. )
  35. var epConn *dnetConnection
  36. func main() {
  37. if reexec.Init() {
  38. return
  39. }
  40. _, stdout, stderr := term.StdStreams()
  41. logrus.SetOutput(stderr)
  42. err := dnetApp(stdout, stderr)
  43. if err != nil {
  44. os.Exit(1)
  45. }
  46. }
  47. func parseConfig(cfgFile string) (*config.Config, error) {
  48. if strings.Trim(cfgFile, " ") == "" {
  49. cfgFile = os.Getenv(cfgFileEnv)
  50. if strings.Trim(cfgFile, " ") == "" {
  51. cfgFile = defaultCfgFile
  52. }
  53. }
  54. return config.ParseConfig(cfgFile)
  55. }
  56. func processConfig(cfg *config.Config) []config.Option {
  57. options := []config.Option{}
  58. if cfg == nil {
  59. return options
  60. }
  61. dn := "bridge"
  62. if strings.TrimSpace(cfg.Daemon.DefaultNetwork) != "" {
  63. dn = cfg.Daemon.DefaultNetwork
  64. }
  65. options = append(options, config.OptionDefaultNetwork(dn))
  66. dd := "bridge"
  67. if strings.TrimSpace(cfg.Daemon.DefaultDriver) != "" {
  68. dd = cfg.Daemon.DefaultDriver
  69. }
  70. options = append(options, config.OptionDefaultDriver(dd))
  71. if cfg.Daemon.Labels != nil {
  72. options = append(options, config.OptionLabels(cfg.Daemon.Labels))
  73. }
  74. if strings.TrimSpace(cfg.GlobalStore.Client.Provider) != "" {
  75. options = append(options, config.OptionKVProvider(cfg.GlobalStore.Client.Provider))
  76. }
  77. if strings.TrimSpace(cfg.GlobalStore.Client.Address) != "" {
  78. options = append(options, config.OptionKVProviderURL(cfg.GlobalStore.Client.Address))
  79. }
  80. return options
  81. }
  82. func dnetApp(stdout, stderr io.Writer) error {
  83. app := cli.NewApp()
  84. app.Name = "dnet"
  85. app.Usage = "A self-sufficient runtime for container networking."
  86. app.Flags = dnetFlags
  87. app.Before = processFlags
  88. app.Commands = dnetCommands
  89. app.Run(os.Args)
  90. return nil
  91. }
  92. func createDefaultNetwork(c libnetwork.NetworkController) {
  93. nw := c.Config().Daemon.DefaultNetwork
  94. d := c.Config().Daemon.DefaultDriver
  95. createOptions := []libnetwork.NetworkOption{}
  96. genericOption := options.Generic{}
  97. if nw != "" && d != "" {
  98. // Bridge driver is special due to legacy reasons
  99. if d == "bridge" {
  100. genericOption[netlabel.GenericData] = map[string]interface{}{
  101. "BridgeName": nw,
  102. }
  103. networkOption := libnetwork.NetworkOptionGeneric(genericOption)
  104. createOptions = append(createOptions, networkOption)
  105. }
  106. _, err := c.NewNetwork(d, nw, createOptions...)
  107. if err != nil {
  108. logrus.Errorf("Error creating default network : %s : %v", nw, err)
  109. }
  110. }
  111. }
  112. type dnetConnection struct {
  113. // proto holds the client protocol i.e. unix.
  114. proto string
  115. // addr holds the client address.
  116. addr string
  117. }
  118. func (d *dnetConnection) dnetDaemon(cfgFile string) error {
  119. if err := startTestDriver(); err != nil {
  120. return fmt.Errorf("failed to start test driver: %v\n", err)
  121. }
  122. cfg, err := parseConfig(cfgFile)
  123. var cOptions []config.Option
  124. if err == nil {
  125. cOptions = processConfig(cfg)
  126. }
  127. controller, err := libnetwork.New(cOptions...)
  128. if err != nil {
  129. fmt.Println("Error starting dnetDaemon :", err)
  130. return err
  131. }
  132. createDefaultNetwork(controller)
  133. httpHandler := api.NewHTTPHandler(controller)
  134. r := mux.NewRouter().StrictSlash(false)
  135. post := r.PathPrefix("/{.*}/networks").Subrouter()
  136. post.Methods("GET", "PUT", "POST", "DELETE").HandlerFunc(httpHandler)
  137. post = r.PathPrefix("/networks").Subrouter()
  138. post.Methods("GET", "PUT", "POST", "DELETE").HandlerFunc(httpHandler)
  139. post = r.PathPrefix("/{.*}/services").Subrouter()
  140. post.Methods("GET", "PUT", "POST", "DELETE").HandlerFunc(httpHandler)
  141. post = r.PathPrefix("/services").Subrouter()
  142. post.Methods("GET", "PUT", "POST", "DELETE").HandlerFunc(httpHandler)
  143. post = r.PathPrefix("/{.*}/sandboxes").Subrouter()
  144. post.Methods("GET", "PUT", "POST", "DELETE").HandlerFunc(httpHandler)
  145. post = r.PathPrefix("/sandboxes").Subrouter()
  146. post.Methods("GET", "PUT", "POST", "DELETE").HandlerFunc(httpHandler)
  147. return http.ListenAndServe(d.addr, r)
  148. }
  149. func startTestDriver() error {
  150. mux := http.NewServeMux()
  151. server := httptest.NewServer(mux)
  152. if server == nil {
  153. return fmt.Errorf("Failed to start a HTTP Server")
  154. }
  155. mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
  156. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  157. fmt.Fprintf(w, `{"Implements": ["%s"]}`, driverapi.NetworkPluginEndpointType)
  158. })
  159. mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  160. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  161. fmt.Fprintf(w, `{"Scope":"global"}`)
  162. })
  163. mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  164. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  165. fmt.Fprintf(w, "null")
  166. })
  167. mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  168. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  169. fmt.Fprintf(w, "null")
  170. })
  171. mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  172. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  173. fmt.Fprintf(w, "null")
  174. })
  175. mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  176. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  177. fmt.Fprintf(w, "null")
  178. })
  179. mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  180. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  181. fmt.Fprintf(w, "null")
  182. })
  183. mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  184. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  185. fmt.Fprintf(w, "null")
  186. })
  187. if err := os.MkdirAll("/usr/share/docker/plugins", 0755); err != nil {
  188. return err
  189. }
  190. if err := ioutil.WriteFile("/usr/share/docker/plugins/test.spec", []byte(server.URL), 0644); err != nil {
  191. return err
  192. }
  193. return nil
  194. }
  195. func newDnetConnection(val string) (*dnetConnection, error) {
  196. url, err := parsers.ParseHost(DefaultHTTPHost, DefaultUnixSocket, val)
  197. if err != nil {
  198. return nil, err
  199. }
  200. protoAddrParts := strings.SplitN(url, "://", 2)
  201. if len(protoAddrParts) != 2 {
  202. return nil, fmt.Errorf("bad format, expected tcp://ADDR")
  203. }
  204. if strings.ToLower(protoAddrParts[0]) != "tcp" {
  205. return nil, fmt.Errorf("dnet currently only supports tcp transport")
  206. }
  207. return &dnetConnection{protoAddrParts[0], protoAddrParts[1]}, nil
  208. }
  209. func (d *dnetConnection) httpCall(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, http.Header, int, error) {
  210. var in io.Reader
  211. in, err := encodeData(data)
  212. if err != nil {
  213. return nil, nil, -1, err
  214. }
  215. req, err := http.NewRequest(method, fmt.Sprintf("%s", path), in)
  216. if err != nil {
  217. return nil, nil, -1, err
  218. }
  219. setupRequestHeaders(method, data, req, headers)
  220. req.URL.Host = d.addr
  221. req.URL.Scheme = "http"
  222. httpClient := &http.Client{}
  223. resp, err := httpClient.Do(req)
  224. statusCode := -1
  225. if resp != nil {
  226. statusCode = resp.StatusCode
  227. }
  228. if err != nil {
  229. return nil, nil, statusCode, fmt.Errorf("error when trying to connect: %v", err)
  230. }
  231. if statusCode < 200 || statusCode >= 400 {
  232. body, err := ioutil.ReadAll(resp.Body)
  233. if err != nil {
  234. return nil, nil, statusCode, err
  235. }
  236. return nil, nil, statusCode, fmt.Errorf("error : %s", bytes.TrimSpace(body))
  237. }
  238. return resp.Body, resp.Header, statusCode, nil
  239. }
  240. func setupRequestHeaders(method string, data interface{}, req *http.Request, headers map[string][]string) {
  241. if data != nil {
  242. if headers == nil {
  243. headers = make(map[string][]string)
  244. }
  245. headers["Content-Type"] = []string{"application/json"}
  246. }
  247. expectedPayload := (method == "POST" || method == "PUT")
  248. if expectedPayload && req.Header.Get("Content-Type") == "" {
  249. req.Header.Set("Content-Type", "text/plain")
  250. }
  251. if headers != nil {
  252. for k, v := range headers {
  253. req.Header[k] = v
  254. }
  255. }
  256. }
  257. func encodeData(data interface{}) (*bytes.Buffer, error) {
  258. params := bytes.NewBuffer(nil)
  259. if data != nil {
  260. if err := json.NewEncoder(params).Encode(data); err != nil {
  261. return nil, err
  262. }
  263. }
  264. return params, nil
  265. }