1// Copyright 2013 go-dockerclient authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package testing provides a fake implementation of the Docker API, useful for
6// testing purpose.
7package testing
8
9import (
10	"archive/tar"
11	"crypto/rand"
12	"crypto/tls"
13	"crypto/x509"
14	"encoding/json"
15	"errors"
16	"fmt"
17	"io"
18	"io/ioutil"
19	mathrand "math/rand"
20	"net"
21	"net/http"
22	libpath "path"
23	"regexp"
24	"strconv"
25	"strings"
26	"sync"
27	"time"
28
29	"github.com/docker/docker/api/types/swarm"
30	"github.com/docker/docker/pkg/stdcopy"
31	"github.com/fsouza/go-dockerclient"
32	"github.com/gorilla/mux"
33)
34
35var nameRegexp = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9_.-]+$`)
36
37// DockerServer represents a programmable, concurrent (not much), HTTP server
38// implementing a fake version of the Docker remote API.
39//
40// It can used in standalone mode, listening for connections or as an arbitrary
41// HTTP handler.
42//
43// For more details on the remote API, check http://goo.gl/G3plxW.
44type DockerServer struct {
45	containers     map[string]*docker.Container
46	contNameToID   map[string]string
47	uploadedFiles  map[string]string
48	execs          []*docker.ExecInspect
49	execMut        sync.RWMutex
50	cMut           sync.RWMutex
51	images         map[string]docker.Image
52	iMut           sync.RWMutex
53	imgIDs         map[string]string
54	networks       []*docker.Network
55	netMut         sync.RWMutex
56	listener       net.Listener
57	mux            *mux.Router
58	hook           func(*http.Request)
59	failures       map[string]string
60	multiFailures  []map[string]string
61	execCallbacks  map[string]func()
62	statsCallbacks map[string]func(string) docker.Stats
63	customHandlers map[string]http.Handler
64	handlerMutex   sync.RWMutex
65	cChan          chan<- *docker.Container
66	volStore       map[string]*volumeCounter
67	volMut         sync.RWMutex
68	swarmMut       sync.RWMutex
69	swarm          *swarm.Swarm
70	swarmServer    *swarmServer
71	nodes          []swarm.Node
72	nodeID         string
73	tasks          []*swarm.Task
74	services       []*swarm.Service
75	nodeRR         int
76	servicePorts   int
77}
78
79type volumeCounter struct {
80	volume docker.Volume
81	count  int
82}
83
84func baseDockerServer() DockerServer {
85	return DockerServer{
86		containers:     make(map[string]*docker.Container),
87		contNameToID:   make(map[string]string),
88		imgIDs:         make(map[string]string),
89		images:         make(map[string]docker.Image),
90		failures:       make(map[string]string),
91		execCallbacks:  make(map[string]func()),
92		statsCallbacks: make(map[string]func(string) docker.Stats),
93		customHandlers: make(map[string]http.Handler),
94		uploadedFiles:  make(map[string]string),
95	}
96}
97
98func buildDockerServer(listener net.Listener, containerChan chan<- *docker.Container, hook func(*http.Request)) *DockerServer {
99	server := baseDockerServer()
100	server.listener = listener
101	server.hook = hook
102	server.cChan = containerChan
103	server.buildMuxer()
104	return &server
105}
106
107// NewServer returns a new instance of the fake server, in standalone mode. Use
108// the method URL to get the URL of the server.
109//
110// It receives the bind address (use 127.0.0.1:0 for getting an available port
111// on the host), a channel of containers and a hook function, that will be
112// called on every request.
113//
114// The fake server will send containers in the channel whenever the container
115// changes its state, via the HTTP API (i.e.: create, start and stop). This
116// channel may be nil, which means that the server won't notify on state
117// changes.
118func NewServer(bind string, containerChan chan<- *docker.Container, hook func(*http.Request)) (*DockerServer, error) {
119	listener, err := net.Listen("tcp", bind)
120	if err != nil {
121		return nil, err
122	}
123	server := buildDockerServer(listener, containerChan, hook)
124	go http.Serve(listener, server)
125	return server, nil
126}
127
128// TLSConfig is the set of options to start the TLS-enabled testing server.
129type TLSConfig struct {
130	CertPath    string
131	CertKeyPath string
132	RootCAPath  string
133}
134
135// NewTLSServer creates and starts a TLS-enabled testing server.
136func NewTLSServer(bind string, containerChan chan<- *docker.Container, hook func(*http.Request), tlsConfig TLSConfig) (*DockerServer, error) {
137	listener, err := net.Listen("tcp", bind)
138	if err != nil {
139		return nil, err
140	}
141	defaultCertificate, err := tls.LoadX509KeyPair(tlsConfig.CertPath, tlsConfig.CertKeyPath)
142	if err != nil {
143		return nil, err
144	}
145	tlsServerConfig := new(tls.Config)
146	tlsServerConfig.Certificates = []tls.Certificate{defaultCertificate}
147	if tlsConfig.RootCAPath != "" {
148		rootCertPEM, err := ioutil.ReadFile(tlsConfig.RootCAPath)
149		if err != nil {
150			return nil, err
151		}
152		certsPool := x509.NewCertPool()
153		certsPool.AppendCertsFromPEM(rootCertPEM)
154		tlsServerConfig.RootCAs = certsPool
155	}
156	tlsListener := tls.NewListener(listener, tlsServerConfig)
157	server := buildDockerServer(tlsListener, containerChan, hook)
158	go http.Serve(tlsListener, server)
159	return server, nil
160}
161
162func (s *DockerServer) notify(container *docker.Container) {
163	if s.cChan != nil {
164		s.cChan <- container
165	}
166}
167
168func (s *DockerServer) buildMuxer() {
169	s.mux = mux.NewRouter()
170	s.mux.Path("/commit").Methods("POST").HandlerFunc(s.handlerWrapper(s.commitContainer))
171	s.mux.Path("/containers/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.listContainers))
172	s.mux.Path("/containers/create").Methods("POST").HandlerFunc(s.handlerWrapper(s.createContainer))
173	s.mux.Path("/containers/{id:.*}/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.inspectContainer))
174	s.mux.Path("/containers/{id:.*}/rename").Methods("POST").HandlerFunc(s.handlerWrapper(s.renameContainer))
175	s.mux.Path("/containers/{id:.*}/top").Methods("GET").HandlerFunc(s.handlerWrapper(s.topContainer))
176	s.mux.Path("/containers/{id:.*}/start").Methods("POST").HandlerFunc(s.handlerWrapper(s.startContainer))
177	s.mux.Path("/containers/{id:.*}/kill").Methods("POST").HandlerFunc(s.handlerWrapper(s.stopContainer))
178	s.mux.Path("/containers/{id:.*}/stop").Methods("POST").HandlerFunc(s.handlerWrapper(s.stopContainer))
179	s.mux.Path("/containers/{id:.*}/pause").Methods("POST").HandlerFunc(s.handlerWrapper(s.pauseContainer))
180	s.mux.Path("/containers/{id:.*}/unpause").Methods("POST").HandlerFunc(s.handlerWrapper(s.unpauseContainer))
181	s.mux.Path("/containers/{id:.*}/wait").Methods("POST").HandlerFunc(s.handlerWrapper(s.waitContainer))
182	s.mux.Path("/containers/{id:.*}/attach").Methods("POST").HandlerFunc(s.handlerWrapper(s.attachContainer))
183	s.mux.Path("/containers/{id:.*}").Methods("DELETE").HandlerFunc(s.handlerWrapper(s.removeContainer))
184	s.mux.Path("/containers/{id:.*}/exec").Methods("POST").HandlerFunc(s.handlerWrapper(s.createExecContainer))
185	s.mux.Path("/containers/{id:.*}/stats").Methods("GET").HandlerFunc(s.handlerWrapper(s.statsContainer))
186	s.mux.Path("/containers/{id:.*}/archive").Methods("PUT").HandlerFunc(s.handlerWrapper(s.uploadToContainer))
187	s.mux.Path("/containers/{id:.*}/archive").Methods("GET").HandlerFunc(s.handlerWrapper(s.downloadFromContainer))
188	s.mux.Path("/containers/{id:.*}/logs").Methods("GET").HandlerFunc(s.handlerWrapper(s.logContainer))
189	s.mux.Path("/exec/{id:.*}/resize").Methods("POST").HandlerFunc(s.handlerWrapper(s.resizeExecContainer))
190	s.mux.Path("/exec/{id:.*}/start").Methods("POST").HandlerFunc(s.handlerWrapper(s.startExecContainer))
191	s.mux.Path("/exec/{id:.*}/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.inspectExecContainer))
192	s.mux.Path("/images/create").Methods("POST").HandlerFunc(s.handlerWrapper(s.pullImage))
193	s.mux.Path("/build").Methods("POST").HandlerFunc(s.handlerWrapper(s.buildImage))
194	s.mux.Path("/images/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.listImages))
195	s.mux.Path("/images/{id:.*}").Methods("DELETE").HandlerFunc(s.handlerWrapper(s.removeImage))
196	s.mux.Path("/images/{name:.*}/json").Methods("GET").HandlerFunc(s.handlerWrapper(s.inspectImage))
197	s.mux.Path("/images/{name:.*}/push").Methods("POST").HandlerFunc(s.handlerWrapper(s.pushImage))
198	s.mux.Path("/images/{name:.*}/tag").Methods("POST").HandlerFunc(s.handlerWrapper(s.tagImage))
199	s.mux.Path("/events").Methods("GET").HandlerFunc(s.listEvents)
200	s.mux.Path("/_ping").Methods("GET").HandlerFunc(s.handlerWrapper(s.pingDocker))
201	s.mux.Path("/images/load").Methods("POST").HandlerFunc(s.handlerWrapper(s.loadImage))
202	s.mux.Path("/images/{id:.*}/get").Methods("GET").HandlerFunc(s.handlerWrapper(s.getImage))
203	s.mux.Path("/networks").Methods("GET").HandlerFunc(s.handlerWrapper(s.listNetworks))
204	s.mux.Path("/networks/{id:.*}").Methods("GET").HandlerFunc(s.handlerWrapper(s.networkInfo))
205	s.mux.Path("/networks/{id:.*}").Methods("DELETE").HandlerFunc(s.handlerWrapper(s.removeNetwork))
206	s.mux.Path("/networks/create").Methods("POST").HandlerFunc(s.handlerWrapper(s.createNetwork))
207	s.mux.Path("/networks/{id:.*}/connect").Methods("POST").HandlerFunc(s.handlerWrapper(s.networksConnect))
208	s.mux.Path("/volumes").Methods("GET").HandlerFunc(s.handlerWrapper(s.listVolumes))
209	s.mux.Path("/volumes/create").Methods("POST").HandlerFunc(s.handlerWrapper(s.createVolume))
210	s.mux.Path("/volumes/{name:.*}").Methods("GET").HandlerFunc(s.handlerWrapper(s.inspectVolume))
211	s.mux.Path("/volumes/{name:.*}").Methods("DELETE").HandlerFunc(s.handlerWrapper(s.removeVolume))
212	s.mux.Path("/info").Methods("GET").HandlerFunc(s.handlerWrapper(s.infoDocker))
213	s.mux.Path("/version").Methods("GET").HandlerFunc(s.handlerWrapper(s.versionDocker))
214	s.mux.Path("/swarm/init").Methods("POST").HandlerFunc(s.handlerWrapper(s.swarmInit))
215	s.mux.Path("/swarm").Methods("GET").HandlerFunc(s.handlerWrapper(s.swarmInspect))
216	s.mux.Path("/swarm/join").Methods("POST").HandlerFunc(s.handlerWrapper(s.swarmJoin))
217	s.mux.Path("/swarm/leave").Methods("POST").HandlerFunc(s.handlerWrapper(s.swarmLeave))
218	s.mux.Path("/nodes/{id:.+}/update").Methods("POST").HandlerFunc(s.handlerWrapper(s.nodeUpdate))
219	s.mux.Path("/nodes/{id:.+}").Methods("GET").HandlerFunc(s.handlerWrapper(s.nodeInspect))
220	s.mux.Path("/nodes/{id:.+}").Methods("DELETE").HandlerFunc(s.handlerWrapper(s.nodeDelete))
221	s.mux.Path("/nodes").Methods("GET").HandlerFunc(s.handlerWrapper(s.nodeList))
222	s.mux.Path("/services/create").Methods("POST").HandlerFunc(s.handlerWrapper(s.serviceCreate))
223	s.mux.Path("/services/{id:.+}").Methods("GET").HandlerFunc(s.handlerWrapper(s.serviceInspect))
224	s.mux.Path("/services").Methods("GET").HandlerFunc(s.handlerWrapper(s.serviceList))
225	s.mux.Path("/services/{id:.+}").Methods("DELETE").HandlerFunc(s.handlerWrapper(s.serviceDelete))
226	s.mux.Path("/services/{id:.+}/update").Methods("POST").HandlerFunc(s.handlerWrapper(s.serviceUpdate))
227	s.mux.Path("/tasks").Methods("GET").HandlerFunc(s.handlerWrapper(s.taskList))
228	s.mux.Path("/tasks/{id:.+}").Methods("GET").HandlerFunc(s.handlerWrapper(s.taskInspect))
229}
230
231// SetHook changes the hook function used by the server.
232//
233// The hook function is a function called on every request.
234func (s *DockerServer) SetHook(hook func(*http.Request)) {
235	s.hook = hook
236}
237
238// PrepareExec adds a callback to a container exec in the fake server.
239//
240// This function will be called whenever the given exec id is started, and the
241// given exec id will remain in the "Running" start while the function is
242// running, so it's useful for emulating an exec that runs for two seconds, for
243// example:
244//
245//    opts := docker.CreateExecOptions{
246//        AttachStdin:  true,
247//        AttachStdout: true,
248//        AttachStderr: true,
249//        Tty:          true,
250//        Cmd:          []string{"/bin/bash", "-l"},
251//    }
252//    // Client points to a fake server.
253//    exec, err := client.CreateExec(opts)
254//    // handle error
255//    server.PrepareExec(exec.ID, func() {time.Sleep(2 * time.Second)})
256//    err = client.StartExec(exec.ID, docker.StartExecOptions{Tty: true}) // will block for 2 seconds
257//    // handle error
258func (s *DockerServer) PrepareExec(id string, callback func()) {
259	s.execCallbacks[id] = callback
260}
261
262// PrepareStats adds a callback that will be called for each container stats
263// call.
264//
265// This callback function will be called multiple times if stream is set to
266// true when stats is called.
267func (s *DockerServer) PrepareStats(id string, callback func(string) docker.Stats) {
268	s.statsCallbacks[id] = callback
269}
270
271// PrepareFailure adds a new expected failure based on a URL regexp it receives
272// an id for the failure.
273func (s *DockerServer) PrepareFailure(id string, urlRegexp string) {
274	s.failures[id] = urlRegexp
275}
276
277// PrepareMultiFailures enqueues a new expected failure based on a URL regexp
278// it receives an id for the failure.
279func (s *DockerServer) PrepareMultiFailures(id string, urlRegexp string) {
280	s.multiFailures = append(s.multiFailures, map[string]string{"error": id, "url": urlRegexp})
281}
282
283// ResetFailure removes an expected failure identified by the given id.
284func (s *DockerServer) ResetFailure(id string) {
285	delete(s.failures, id)
286}
287
288// ResetMultiFailures removes all enqueued failures.
289func (s *DockerServer) ResetMultiFailures() {
290	s.multiFailures = []map[string]string{}
291}
292
293// CustomHandler registers a custom handler for a specific path.
294//
295// For example:
296//
297//     server.CustomHandler("/containers/json", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
298//         http.Error(w, "Something wrong is not right", http.StatusInternalServerError)
299//     }))
300func (s *DockerServer) CustomHandler(path string, handler http.Handler) {
301	s.handlerMutex.Lock()
302	s.customHandlers[path] = handler
303	s.handlerMutex.Unlock()
304}
305
306// MutateContainer changes the state of a container, returning an error if the
307// given id does not match to any container "running" in the server.
308func (s *DockerServer) MutateContainer(id string, state docker.State) error {
309	s.cMut.Lock()
310	defer s.cMut.Unlock()
311	if container, ok := s.containers[id]; ok {
312		container.State = state
313		return nil
314	}
315	return errors.New("container not found")
316}
317
318// Stop stops the server.
319func (s *DockerServer) Stop() {
320	if s.listener != nil {
321		s.listener.Close()
322	}
323	if s.swarmServer != nil {
324		s.swarmServer.listener.Close()
325	}
326}
327
328// URL returns the HTTP URL of the server.
329func (s *DockerServer) URL() string {
330	if s.listener == nil {
331		return ""
332	}
333	return "http://" + s.listener.Addr().String() + "/"
334}
335
336// ServeHTTP handles HTTP requests sent to the server.
337func (s *DockerServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
338	s.handlerMutex.RLock()
339	defer s.handlerMutex.RUnlock()
340	for re, handler := range s.customHandlers {
341		if m, _ := regexp.MatchString(re, r.URL.Path); m {
342			handler.ServeHTTP(w, r)
343			return
344		}
345	}
346	s.mux.ServeHTTP(w, r)
347	if s.hook != nil {
348		s.hook(r)
349	}
350}
351
352// DefaultHandler returns default http.Handler mux, it allows customHandlers to
353// call the default behavior if wanted.
354func (s *DockerServer) DefaultHandler() http.Handler {
355	return s.mux
356}
357
358func (s *DockerServer) handlerWrapper(f http.HandlerFunc) http.HandlerFunc {
359	return func(w http.ResponseWriter, r *http.Request) {
360		for errorID, urlRegexp := range s.failures {
361			matched, err := regexp.MatchString(urlRegexp, r.URL.Path)
362			if err != nil {
363				http.Error(w, err.Error(), http.StatusBadRequest)
364				return
365			}
366			if !matched {
367				continue
368			}
369			http.Error(w, errorID, http.StatusBadRequest)
370			return
371		}
372		for i, failure := range s.multiFailures {
373			matched, err := regexp.MatchString(failure["url"], r.URL.Path)
374			if err != nil {
375				http.Error(w, err.Error(), http.StatusBadRequest)
376				return
377			}
378			if !matched {
379				continue
380			}
381			http.Error(w, failure["error"], http.StatusBadRequest)
382			s.multiFailures = append(s.multiFailures[:i], s.multiFailures[i+1:]...)
383			return
384		}
385		f(w, r)
386	}
387}
388
389func (s *DockerServer) listContainers(w http.ResponseWriter, r *http.Request) {
390	all := r.URL.Query().Get("all")
391	filtersRaw := r.FormValue("filters")
392	filters := make(map[string][]string)
393	json.Unmarshal([]byte(filtersRaw), &filters)
394	labelFilters := make(map[string]*string)
395	for _, f := range filters["label"] {
396		parts := strings.Split(f, "=")
397		if len(parts) == 2 {
398			labelFilters[parts[0]] = &parts[1]
399			continue
400		}
401		labelFilters[parts[0]] = nil
402	}
403	s.cMut.RLock()
404	result := make([]docker.APIContainers, 0, len(s.containers))
405loop:
406	for _, container := range s.containers {
407		if all == "1" || container.State.Running {
408			var ports []docker.APIPort
409			if container.NetworkSettings != nil {
410				ports = container.NetworkSettings.PortMappingAPI()
411			}
412			for l, fv := range labelFilters {
413				lv, ok := container.Config.Labels[l]
414				if !ok {
415					continue loop
416				}
417				if fv != nil && lv != *fv {
418					continue loop
419				}
420			}
421			result = append(result, docker.APIContainers{
422				ID:      container.ID,
423				Image:   container.Image,
424				Command: fmt.Sprintf("%s %s", container.Path, strings.Join(container.Args, " ")),
425				Created: container.Created.Unix(),
426				Status:  container.State.String(),
427				State:   container.State.StateString(),
428				Ports:   ports,
429				Names:   []string{fmt.Sprintf("/%s", container.Name)},
430			})
431		}
432	}
433	s.cMut.RUnlock()
434	w.Header().Set("Content-Type", "application/json")
435	w.WriteHeader(http.StatusOK)
436	json.NewEncoder(w).Encode(result)
437}
438
439func (s *DockerServer) listImages(w http.ResponseWriter, r *http.Request) {
440	s.cMut.RLock()
441	result := make([]docker.APIImages, len(s.images))
442	i := 0
443	for _, image := range s.images {
444		result[i] = docker.APIImages{
445			ID:      image.ID,
446			Created: image.Created.Unix(),
447		}
448		for tag, id := range s.imgIDs {
449			if id == image.ID {
450				result[i].RepoTags = append(result[i].RepoTags, tag)
451			}
452		}
453		i++
454	}
455	s.cMut.RUnlock()
456	w.Header().Set("Content-Type", "application/json")
457	w.WriteHeader(http.StatusOK)
458	json.NewEncoder(w).Encode(result)
459}
460
461func (s *DockerServer) findImage(id string) (string, error) {
462	s.iMut.RLock()
463	defer s.iMut.RUnlock()
464	image, ok := s.imgIDs[id]
465	if ok {
466		return image, nil
467	}
468	if _, ok := s.images[id]; ok {
469		return id, nil
470	}
471	return "", errors.New("No such image")
472}
473
474func (s *DockerServer) createContainer(w http.ResponseWriter, r *http.Request) {
475	var config struct {
476		*docker.Config
477		HostConfig *docker.HostConfig
478	}
479	defer r.Body.Close()
480	err := json.NewDecoder(r.Body).Decode(&config)
481	if err != nil {
482		http.Error(w, err.Error(), http.StatusBadRequest)
483		return
484	}
485	name := r.URL.Query().Get("name")
486	if name != "" && !nameRegexp.MatchString(name) {
487		http.Error(w, "Invalid container name", http.StatusInternalServerError)
488		return
489	}
490	imageID, err := s.findImage(config.Image)
491	if err != nil {
492		http.Error(w, err.Error(), http.StatusNotFound)
493		return
494	}
495	ports := map[docker.Port][]docker.PortBinding{}
496	for port := range config.ExposedPorts {
497		ports[port] = []docker.PortBinding{{
498			HostIP:   "0.0.0.0",
499			HostPort: strconv.Itoa(mathrand.Int() % 0xffff),
500		}}
501	}
502
503	//the container may not have cmd when using a Dockerfile
504	var path string
505	var args []string
506	if len(config.Cmd) == 1 {
507		path = config.Cmd[0]
508	} else if len(config.Cmd) > 1 {
509		path = config.Cmd[0]
510		args = config.Cmd[1:]
511	}
512
513	generatedID := s.generateID()
514	config.Config.Hostname = generatedID[:12]
515	container := docker.Container{
516		Name:       name,
517		ID:         generatedID,
518		Created:    time.Now(),
519		Path:       path,
520		Args:       args,
521		Config:     config.Config,
522		HostConfig: config.HostConfig,
523		State: docker.State{
524			Running:  false,
525			Pid:      mathrand.Int() % 50000,
526			ExitCode: 0,
527		},
528		Image: config.Image,
529		NetworkSettings: &docker.NetworkSettings{
530			IPAddress:   fmt.Sprintf("172.16.42.%d", mathrand.Int()%250+2),
531			IPPrefixLen: 24,
532			Gateway:     "172.16.42.1",
533			Bridge:      "docker0",
534			Ports:       ports,
535		},
536	}
537	s.cMut.Lock()
538	if val, ok := s.uploadedFiles[imageID]; ok {
539		s.uploadedFiles[container.ID] = val
540	}
541	if container.Name != "" {
542		_, err = s.findContainerWithLock(container.Name, false)
543		if err == nil {
544			defer s.cMut.Unlock()
545			http.Error(w, "there's already a container with this name", http.StatusConflict)
546			return
547		}
548	}
549	s.addContainer(&container)
550	s.cMut.Unlock()
551	w.WriteHeader(http.StatusCreated)
552	s.notify(&container)
553
554	json.NewEncoder(w).Encode(container)
555}
556
557func (s *DockerServer) addContainer(container *docker.Container) {
558	s.containers[container.ID] = container
559	if container.Name != "" {
560		s.contNameToID[container.Name] = container.ID
561	}
562}
563
564func (s *DockerServer) generateID() string {
565	var buf [16]byte
566	rand.Read(buf[:])
567	return fmt.Sprintf("%x", buf)
568}
569
570func (s *DockerServer) renameContainer(w http.ResponseWriter, r *http.Request) {
571	id := mux.Vars(r)["id"]
572	s.cMut.Lock()
573	defer s.cMut.Unlock()
574	container, err := s.findContainerWithLock(id, false)
575	if err != nil {
576		http.Error(w, err.Error(), http.StatusNotFound)
577		return
578	}
579	delete(s.contNameToID, container.Name)
580	container.Name = r.URL.Query().Get("name")
581	s.contNameToID[container.Name] = container.ID
582	w.WriteHeader(http.StatusNoContent)
583}
584
585func (s *DockerServer) inspectContainer(w http.ResponseWriter, r *http.Request) {
586	id := mux.Vars(r)["id"]
587	container, err := s.findContainer(id)
588	if err != nil {
589		http.Error(w, err.Error(), http.StatusNotFound)
590		return
591	}
592	w.Header().Set("Content-Type", "application/json")
593	w.WriteHeader(http.StatusOK)
594	s.cMut.RLock()
595	defer s.cMut.RUnlock()
596	json.NewEncoder(w).Encode(container)
597}
598
599func (s *DockerServer) statsContainer(w http.ResponseWriter, r *http.Request) {
600	id := mux.Vars(r)["id"]
601	_, err := s.findContainer(id)
602	if err != nil {
603		http.Error(w, err.Error(), http.StatusNotFound)
604		return
605	}
606	stream, _ := strconv.ParseBool(r.URL.Query().Get("stream"))
607	callback := s.statsCallbacks[id]
608	w.Header().Set("Content-Type", "application/json")
609	w.WriteHeader(http.StatusOK)
610	encoder := json.NewEncoder(w)
611	for {
612		var stats docker.Stats
613		if callback != nil {
614			stats = callback(id)
615		}
616		encoder.Encode(stats)
617		if !stream {
618			break
619		}
620	}
621}
622
623func (s *DockerServer) uploadToContainer(w http.ResponseWriter, r *http.Request) {
624	id := mux.Vars(r)["id"]
625	_, err := s.findContainer(id)
626	if err != nil {
627		http.Error(w, err.Error(), http.StatusNotFound)
628		return
629	}
630	path := r.URL.Query().Get("path")
631	if r.Body != nil {
632		tr := tar.NewReader(r.Body)
633		if hdr, _ := tr.Next(); hdr != nil {
634			path = libpath.Join(path, hdr.Name)
635		}
636	}
637	s.cMut.Lock()
638	s.uploadedFiles[id] = path
639	s.cMut.Unlock()
640	w.WriteHeader(http.StatusOK)
641}
642
643func (s *DockerServer) downloadFromContainer(w http.ResponseWriter, r *http.Request) {
644	id := mux.Vars(r)["id"]
645	_, err := s.findContainer(id)
646	if err != nil {
647		http.Error(w, err.Error(), http.StatusNotFound)
648		return
649	}
650	path := r.URL.Query().Get("path")
651	s.cMut.RLock()
652	val, ok := s.uploadedFiles[id]
653	s.cMut.RUnlock()
654	if !ok || val != path {
655		w.WriteHeader(http.StatusNotFound)
656		fmt.Fprintf(w, "Path %s not found", path)
657		return
658	}
659	w.Header().Set("Content-Type", "application/x-tar")
660	w.WriteHeader(http.StatusOK)
661}
662
663func (s *DockerServer) topContainer(w http.ResponseWriter, r *http.Request) {
664	id := mux.Vars(r)["id"]
665	container, err := s.findContainer(id)
666	if err != nil {
667		http.Error(w, err.Error(), http.StatusNotFound)
668		return
669	}
670	s.cMut.RLock()
671	defer s.cMut.RUnlock()
672	if !container.State.Running {
673		w.WriteHeader(http.StatusInternalServerError)
674		fmt.Fprintf(w, "Container %s is not running", id)
675		return
676	}
677	w.Header().Set("Content-Type", "application/json")
678	w.WriteHeader(http.StatusOK)
679	result := docker.TopResult{
680		Titles: []string{"UID", "PID", "PPID", "C", "STIME", "TTY", "TIME", "CMD"},
681		Processes: [][]string{
682			{"root", "7535", "7516", "0", "03:20", "?", "00:00:00", container.Path + " " + strings.Join(container.Args, " ")},
683		},
684	}
685	json.NewEncoder(w).Encode(result)
686}
687
688func (s *DockerServer) startContainer(w http.ResponseWriter, r *http.Request) {
689	id := mux.Vars(r)["id"]
690	container, err := s.findContainer(id)
691	if err != nil {
692		http.Error(w, err.Error(), http.StatusNotFound)
693		return
694	}
695	s.cMut.Lock()
696	defer s.cMut.Unlock()
697	defer r.Body.Close()
698	if container.State.Running {
699		http.Error(w, "", http.StatusNotModified)
700		return
701	}
702	var hostConfig *docker.HostConfig
703	err = json.NewDecoder(r.Body).Decode(&hostConfig)
704	if err != nil && err != io.EOF {
705		http.Error(w, err.Error(), http.StatusInternalServerError)
706		return
707	}
708	if hostConfig == nil {
709		hostConfig = container.HostConfig
710	} else {
711		container.HostConfig = hostConfig
712	}
713	if hostConfig != nil && len(hostConfig.PortBindings) > 0 {
714		ports := map[docker.Port][]docker.PortBinding{}
715		for key, items := range hostConfig.PortBindings {
716			bindings := make([]docker.PortBinding, len(items))
717			for i := range items {
718				binding := docker.PortBinding{
719					HostIP:   items[i].HostIP,
720					HostPort: items[i].HostPort,
721				}
722				if binding.HostIP == "" {
723					binding.HostIP = "0.0.0.0"
724				}
725				if binding.HostPort == "" {
726					binding.HostPort = strconv.Itoa(mathrand.Int() % 0xffff)
727				}
728				bindings[i] = binding
729			}
730			ports[key] = bindings
731		}
732		container.NetworkSettings.Ports = ports
733	}
734	container.State.Running = true
735	container.State.StartedAt = time.Now()
736	s.notify(container)
737}
738
739func (s *DockerServer) stopContainer(w http.ResponseWriter, r *http.Request) {
740	id := mux.Vars(r)["id"]
741	container, err := s.findContainer(id)
742	if err != nil {
743		http.Error(w, err.Error(), http.StatusNotFound)
744		return
745	}
746	s.cMut.Lock()
747	defer s.cMut.Unlock()
748	if !container.State.Running {
749		http.Error(w, "Container not running", http.StatusBadRequest)
750		return
751	}
752	w.WriteHeader(http.StatusNoContent)
753	container.State.Running = false
754	s.notify(container)
755}
756
757func (s *DockerServer) pauseContainer(w http.ResponseWriter, r *http.Request) {
758	id := mux.Vars(r)["id"]
759	container, err := s.findContainer(id)
760	if err != nil {
761		http.Error(w, err.Error(), http.StatusNotFound)
762		return
763	}
764	s.cMut.Lock()
765	defer s.cMut.Unlock()
766	if container.State.Paused {
767		http.Error(w, "Container already paused", http.StatusBadRequest)
768		return
769	}
770	w.WriteHeader(http.StatusNoContent)
771	container.State.Paused = true
772}
773
774func (s *DockerServer) unpauseContainer(w http.ResponseWriter, r *http.Request) {
775	id := mux.Vars(r)["id"]
776	container, err := s.findContainer(id)
777	if err != nil {
778		http.Error(w, err.Error(), http.StatusNotFound)
779		return
780	}
781	s.cMut.Lock()
782	defer s.cMut.Unlock()
783	if !container.State.Paused {
784		http.Error(w, "Container not paused", http.StatusBadRequest)
785		return
786	}
787	w.WriteHeader(http.StatusNoContent)
788	container.State.Paused = false
789}
790
791func (s *DockerServer) attachContainer(w http.ResponseWriter, r *http.Request) {
792	id := mux.Vars(r)["id"]
793	container, err := s.findContainer(id)
794	if err != nil {
795		http.Error(w, err.Error(), http.StatusNotFound)
796		return
797	}
798	hijacker, ok := w.(http.Hijacker)
799	if !ok {
800		http.Error(w, "cannot hijack connection", http.StatusInternalServerError)
801		return
802	}
803	w.Header().Set("Content-Type", "application/vnd.docker.raw-stream")
804	w.WriteHeader(http.StatusOK)
805	conn, _, err := hijacker.Hijack()
806	if err != nil {
807		http.Error(w, err.Error(), http.StatusInternalServerError)
808		return
809	}
810	wg := sync.WaitGroup{}
811	if r.URL.Query().Get("stdin") == "1" {
812		wg.Add(1)
813		go func() {
814			ioutil.ReadAll(conn)
815			wg.Done()
816		}()
817	}
818	outStream := stdcopy.NewStdWriter(conn, stdcopy.Stdout)
819	s.cMut.RLock()
820	if container.State.Running {
821		fmt.Fprintf(outStream, "Container is running\n")
822	} else {
823		fmt.Fprintf(outStream, "Container is not running\n")
824	}
825	s.cMut.RUnlock()
826	fmt.Fprintln(outStream, "What happened?")
827	fmt.Fprintln(outStream, "Something happened")
828	wg.Wait()
829	if r.URL.Query().Get("stream") == "1" {
830		for {
831			time.Sleep(1e6)
832			s.cMut.RLock()
833			if !container.State.StartedAt.IsZero() && !container.State.Running {
834				s.cMut.RUnlock()
835				break
836			}
837			s.cMut.RUnlock()
838		}
839	}
840	conn.Close()
841}
842
843func (s *DockerServer) waitContainer(w http.ResponseWriter, r *http.Request) {
844	id := mux.Vars(r)["id"]
845	container, err := s.findContainer(id)
846	if err != nil {
847		http.Error(w, err.Error(), http.StatusNotFound)
848		return
849	}
850	var exitCode int
851	for {
852		time.Sleep(1e6)
853		s.cMut.RLock()
854		if !container.State.Running {
855			exitCode = container.State.ExitCode
856			s.cMut.RUnlock()
857			break
858		}
859		s.cMut.RUnlock()
860	}
861	result := map[string]int{"StatusCode": exitCode}
862	json.NewEncoder(w).Encode(result)
863}
864
865func (s *DockerServer) removeContainer(w http.ResponseWriter, r *http.Request) {
866	id := mux.Vars(r)["id"]
867	force := r.URL.Query().Get("force")
868	s.cMut.Lock()
869	defer s.cMut.Unlock()
870	container, err := s.findContainerWithLock(id, false)
871	if err != nil {
872		http.Error(w, err.Error(), http.StatusNotFound)
873		return
874	}
875	if container.State.Running && force != "1" {
876		msg := "Error: API error (406): Impossible to remove a running container, please stop it first"
877		http.Error(w, msg, http.StatusInternalServerError)
878		return
879	}
880	w.WriteHeader(http.StatusNoContent)
881	delete(s.containers, container.ID)
882	delete(s.contNameToID, container.Name)
883}
884
885func (s *DockerServer) commitContainer(w http.ResponseWriter, r *http.Request) {
886	id := r.URL.Query().Get("container")
887	container, err := s.findContainer(id)
888	if err != nil {
889		http.Error(w, err.Error(), http.StatusNotFound)
890		return
891	}
892	config := new(docker.Config)
893	runConfig := r.URL.Query().Get("run")
894	if runConfig != "" {
895		err = json.Unmarshal([]byte(runConfig), config)
896		if err != nil {
897			http.Error(w, err.Error(), http.StatusBadRequest)
898			return
899		}
900	}
901	w.WriteHeader(http.StatusOK)
902	image := docker.Image{
903		ID:        "img-" + container.ID,
904		Parent:    container.Image,
905		Container: container.ID,
906		Comment:   r.URL.Query().Get("m"),
907		Author:    r.URL.Query().Get("author"),
908		Config:    config,
909	}
910	repository := r.URL.Query().Get("repo")
911	tag := r.URL.Query().Get("tag")
912	s.iMut.Lock()
913	s.images[image.ID] = image
914	if repository != "" {
915		if tag != "" {
916			repository += ":" + tag
917		}
918		s.imgIDs[repository] = image.ID
919	}
920	s.iMut.Unlock()
921	s.cMut.Lock()
922	if val, ok := s.uploadedFiles[container.ID]; ok {
923		s.uploadedFiles[image.ID] = val
924	}
925	s.cMut.Unlock()
926	fmt.Fprintf(w, `{"ID":%q}`, image.ID)
927}
928
929func (s *DockerServer) findContainer(idOrName string) (*docker.Container, error) {
930	return s.findContainerWithLock(idOrName, true)
931}
932
933func (s *DockerServer) findContainerWithLock(idOrName string, shouldLock bool) (*docker.Container, error) {
934	if shouldLock {
935		s.cMut.RLock()
936		defer s.cMut.RUnlock()
937	}
938	if contID, ok := s.contNameToID[idOrName]; ok {
939		idOrName = contID
940	}
941	if cont, ok := s.containers[idOrName]; ok {
942		return cont, nil
943	}
944	return nil, errors.New("No such container")
945}
946
947func (s *DockerServer) logContainer(w http.ResponseWriter, r *http.Request) {
948	id := mux.Vars(r)["id"]
949	container, err := s.findContainer(id)
950	if err != nil {
951		http.Error(w, err.Error(), http.StatusNotFound)
952		return
953	}
954	w.Header().Set("Content-Type", "application/vnd.docker.raw-stream")
955	w.WriteHeader(http.StatusOK)
956	s.cMut.RLock()
957	if container.State.Running {
958		fmt.Fprintf(w, "Container is running\n")
959	} else {
960		fmt.Fprintf(w, "Container is not running\n")
961	}
962	s.cMut.RUnlock()
963	fmt.Fprintln(w, "What happened?")
964	fmt.Fprintln(w, "Something happened")
965	if r.URL.Query().Get("follow") == "1" {
966		for {
967			time.Sleep(1e6)
968			s.cMut.RLock()
969			if !container.State.StartedAt.IsZero() && !container.State.Running {
970				s.cMut.RUnlock()
971				break
972			}
973			s.cMut.RUnlock()
974		}
975	}
976}
977
978func (s *DockerServer) buildImage(w http.ResponseWriter, r *http.Request) {
979	if ct := r.Header.Get("Content-Type"); ct == "application/tar" {
980		gotDockerFile := false
981		tr := tar.NewReader(r.Body)
982		for {
983			header, err := tr.Next()
984			if err != nil {
985				break
986			}
987			if header.Name == "Dockerfile" {
988				gotDockerFile = true
989			}
990		}
991		if !gotDockerFile {
992			w.WriteHeader(http.StatusBadRequest)
993			w.Write([]byte("miss Dockerfile"))
994			return
995		}
996	}
997	//we did not use that Dockerfile to build image cause we are a fake Docker daemon
998	image := docker.Image{
999		ID:      s.generateID(),
1000		Created: time.Now(),
1001	}
1002
1003	query := r.URL.Query()
1004	repository := image.ID
1005	if t := query.Get("t"); t != "" {
1006		repository = t
1007	}
1008	s.iMut.Lock()
1009	s.images[image.ID] = image
1010	s.imgIDs[repository] = image.ID
1011	s.iMut.Unlock()
1012	w.Write([]byte(fmt.Sprintf("Successfully built %s", image.ID)))
1013}
1014
1015func (s *DockerServer) pullImage(w http.ResponseWriter, r *http.Request) {
1016	fromImageName := r.URL.Query().Get("fromImage")
1017	tag := r.URL.Query().Get("tag")
1018	if fromImageName != "" {
1019		if tag != "" {
1020			separator := ":"
1021			if strings.HasPrefix(tag, "sha256") {
1022				separator = "@"
1023			}
1024			fromImageName = fmt.Sprintf("%s%s%s", fromImageName, separator, tag)
1025		}
1026	}
1027	image := docker.Image{
1028		ID:     s.generateID(),
1029		Config: &docker.Config{},
1030	}
1031	s.iMut.Lock()
1032	if _, exists := s.imgIDs[fromImageName]; fromImageName == "" || !exists {
1033		s.images[image.ID] = image
1034		if fromImageName != "" {
1035			s.imgIDs[fromImageName] = image.ID
1036		}
1037	}
1038	s.iMut.Unlock()
1039}
1040
1041func (s *DockerServer) pushImage(w http.ResponseWriter, r *http.Request) {
1042	name := mux.Vars(r)["name"]
1043	tag := r.URL.Query().Get("tag")
1044	if tag != "" {
1045		name += ":" + tag
1046	}
1047	s.iMut.RLock()
1048	if _, ok := s.imgIDs[name]; !ok {
1049		s.iMut.RUnlock()
1050		http.Error(w, "No such image", http.StatusNotFound)
1051		return
1052	}
1053	s.iMut.RUnlock()
1054	fmt.Fprintln(w, "Pushing...")
1055	fmt.Fprintln(w, "Pushed")
1056}
1057
1058func (s *DockerServer) tagImage(w http.ResponseWriter, r *http.Request) {
1059	name := mux.Vars(r)["name"]
1060	id, err := s.findImage(name)
1061	if err != nil {
1062		http.Error(w, "No such image", http.StatusNotFound)
1063		return
1064	}
1065	s.iMut.Lock()
1066	defer s.iMut.Unlock()
1067	newRepo := r.URL.Query().Get("repo")
1068	newTag := r.URL.Query().Get("tag")
1069	if newTag != "" {
1070		newRepo += ":" + newTag
1071	}
1072	s.imgIDs[newRepo] = id
1073	w.WriteHeader(http.StatusCreated)
1074}
1075
1076func (s *DockerServer) removeImage(w http.ResponseWriter, r *http.Request) {
1077	id := mux.Vars(r)["id"]
1078	s.iMut.Lock()
1079	defer s.iMut.Unlock()
1080	var tag string
1081	if img, ok := s.imgIDs[id]; ok {
1082		id, tag = img, id
1083	}
1084	var tags []string
1085	for tag, taggedID := range s.imgIDs {
1086		if taggedID == id {
1087			tags = append(tags, tag)
1088		}
1089	}
1090	_, ok := s.images[id]
1091	if !ok {
1092		http.Error(w, "No such image", http.StatusNotFound)
1093		return
1094	}
1095	if tag == "" && len(tags) > 1 {
1096		http.Error(w, "image is referenced in multiple repositories", http.StatusConflict)
1097		return
1098	}
1099	w.WriteHeader(http.StatusNoContent)
1100	if tag == "" {
1101		// delete called with image ID
1102		for _, t := range tags {
1103			delete(s.imgIDs, t)
1104		}
1105		delete(s.images, id)
1106	} else {
1107		// delete called with image repository name
1108		delete(s.imgIDs, tag)
1109		if len(tags) == 1 {
1110			delete(s.images, id)
1111		}
1112	}
1113}
1114
1115func (s *DockerServer) inspectImage(w http.ResponseWriter, r *http.Request) {
1116	name := mux.Vars(r)["name"]
1117	s.iMut.RLock()
1118	defer s.iMut.RUnlock()
1119	if id, ok := s.imgIDs[name]; ok {
1120		name = id
1121	}
1122	img, ok := s.images[name]
1123	if !ok {
1124		http.Error(w, "not found", http.StatusNotFound)
1125		return
1126	}
1127	w.Header().Set("Content-Type", "application/json")
1128	w.WriteHeader(http.StatusOK)
1129	json.NewEncoder(w).Encode(img)
1130}
1131
1132func (s *DockerServer) listEvents(w http.ResponseWriter, r *http.Request) {
1133	w.Header().Set("Content-Type", "application/json")
1134	var events [][]byte
1135	count := mathrand.Intn(20)
1136	for i := 0; i < count; i++ {
1137		data, err := json.Marshal(s.generateEvent())
1138		if err != nil {
1139			w.WriteHeader(http.StatusInternalServerError)
1140			return
1141		}
1142		events = append(events, data)
1143	}
1144	w.WriteHeader(http.StatusOK)
1145	for _, d := range events {
1146		fmt.Fprintln(w, d)
1147		time.Sleep(time.Duration(mathrand.Intn(200)) * time.Millisecond)
1148	}
1149}
1150
1151func (s *DockerServer) pingDocker(w http.ResponseWriter, r *http.Request) {
1152	w.WriteHeader(http.StatusOK)
1153}
1154
1155func (s *DockerServer) generateEvent() *docker.APIEvents {
1156	var eventType string
1157	switch mathrand.Intn(4) {
1158	case 0:
1159		eventType = "create"
1160	case 1:
1161		eventType = "start"
1162	case 2:
1163		eventType = "stop"
1164	case 3:
1165		eventType = "destroy"
1166	}
1167	return &docker.APIEvents{
1168		ID:     s.generateID(),
1169		Status: eventType,
1170		From:   "mybase:latest",
1171		Time:   time.Now().Unix(),
1172	}
1173}
1174
1175func (s *DockerServer) loadImage(w http.ResponseWriter, r *http.Request) {
1176	w.WriteHeader(http.StatusOK)
1177}
1178
1179func (s *DockerServer) getImage(w http.ResponseWriter, r *http.Request) {
1180	w.WriteHeader(http.StatusOK)
1181	w.Header().Set("Content-Type", "application/tar")
1182}
1183
1184func (s *DockerServer) createExecContainer(w http.ResponseWriter, r *http.Request) {
1185	id := mux.Vars(r)["id"]
1186	container, err := s.findContainer(id)
1187	if err != nil {
1188		http.Error(w, err.Error(), http.StatusNotFound)
1189		return
1190	}
1191
1192	execID := s.generateID()
1193	s.cMut.Lock()
1194	container.ExecIDs = append(container.ExecIDs, execID)
1195	s.cMut.Unlock()
1196
1197	exec := docker.ExecInspect{
1198		ID:          execID,
1199		ContainerID: container.ID,
1200	}
1201
1202	var params docker.CreateExecOptions
1203	err = json.NewDecoder(r.Body).Decode(&params)
1204	if err != nil {
1205		http.Error(w, err.Error(), http.StatusInternalServerError)
1206		return
1207	}
1208	if len(params.Cmd) > 0 {
1209		exec.ProcessConfig.EntryPoint = params.Cmd[0]
1210		if len(params.Cmd) > 1 {
1211			exec.ProcessConfig.Arguments = params.Cmd[1:]
1212		}
1213	}
1214
1215	exec.ProcessConfig.User = params.User
1216	exec.ProcessConfig.Tty = params.Tty
1217
1218	s.execMut.Lock()
1219	s.execs = append(s.execs, &exec)
1220	s.execMut.Unlock()
1221	w.WriteHeader(http.StatusOK)
1222	w.Header().Set("Content-Type", "application/json")
1223	json.NewEncoder(w).Encode(map[string]string{"Id": exec.ID})
1224}
1225
1226func (s *DockerServer) startExecContainer(w http.ResponseWriter, r *http.Request) {
1227	id := mux.Vars(r)["id"]
1228	if exec, err := s.getExec(id, false); err == nil {
1229		s.execMut.Lock()
1230		exec.Running = true
1231		s.execMut.Unlock()
1232		if callback, ok := s.execCallbacks[id]; ok {
1233			callback()
1234			delete(s.execCallbacks, id)
1235		} else if callback, ok := s.execCallbacks["*"]; ok {
1236			callback()
1237			delete(s.execCallbacks, "*")
1238		}
1239		s.execMut.Lock()
1240		exec.Running = false
1241		s.execMut.Unlock()
1242		w.WriteHeader(http.StatusOK)
1243		return
1244	}
1245	w.WriteHeader(http.StatusNotFound)
1246}
1247
1248func (s *DockerServer) resizeExecContainer(w http.ResponseWriter, r *http.Request) {
1249	id := mux.Vars(r)["id"]
1250	if _, err := s.getExec(id, false); err == nil {
1251		w.WriteHeader(http.StatusOK)
1252		return
1253	}
1254	w.WriteHeader(http.StatusNotFound)
1255}
1256
1257func (s *DockerServer) inspectExecContainer(w http.ResponseWriter, r *http.Request) {
1258	id := mux.Vars(r)["id"]
1259	if exec, err := s.getExec(id, true); err == nil {
1260		w.WriteHeader(http.StatusOK)
1261		w.Header().Set("Content-Type", "application/json")
1262		json.NewEncoder(w).Encode(exec)
1263		return
1264	}
1265	w.WriteHeader(http.StatusNotFound)
1266}
1267
1268func (s *DockerServer) getExec(id string, copy bool) (*docker.ExecInspect, error) {
1269	s.execMut.RLock()
1270	defer s.execMut.RUnlock()
1271	for _, exec := range s.execs {
1272		if exec.ID == id {
1273			if copy {
1274				cp := *exec
1275				exec = &cp
1276			}
1277			return exec, nil
1278		}
1279	}
1280	return nil, errors.New("exec not found")
1281}
1282
1283func (s *DockerServer) findNetwork(idOrName string) (*docker.Network, int, error) {
1284	s.netMut.RLock()
1285	defer s.netMut.RUnlock()
1286	for i, network := range s.networks {
1287		if network.ID == idOrName || network.Name == idOrName {
1288			return network, i, nil
1289		}
1290	}
1291	return nil, -1, errors.New("No such network")
1292}
1293
1294func (s *DockerServer) listNetworks(w http.ResponseWriter, r *http.Request) {
1295	s.netMut.RLock()
1296	result := make([]docker.Network, 0, len(s.networks))
1297	for _, network := range s.networks {
1298		result = append(result, *network)
1299	}
1300	s.netMut.RUnlock()
1301	w.Header().Set("Content-Type", "application/json")
1302	w.WriteHeader(http.StatusOK)
1303	json.NewEncoder(w).Encode(result)
1304}
1305
1306func (s *DockerServer) networkInfo(w http.ResponseWriter, r *http.Request) {
1307	id := mux.Vars(r)["id"]
1308	network, _, err := s.findNetwork(id)
1309	if err != nil {
1310		http.Error(w, err.Error(), http.StatusNotFound)
1311		return
1312	}
1313	w.Header().Set("Content-Type", "application/json")
1314	w.WriteHeader(http.StatusOK)
1315	json.NewEncoder(w).Encode(network)
1316}
1317
1318// isValidName validates configuration objects supported by libnetwork
1319func isValidName(name string) bool {
1320	if name == "" || strings.Contains(name, ".") {
1321		return false
1322	}
1323	return true
1324}
1325
1326func (s *DockerServer) createNetwork(w http.ResponseWriter, r *http.Request) {
1327	var config *docker.CreateNetworkOptions
1328	defer r.Body.Close()
1329	err := json.NewDecoder(r.Body).Decode(&config)
1330	if err != nil {
1331		http.Error(w, err.Error(), http.StatusBadRequest)
1332		return
1333	}
1334	if !isValidName(config.Name) {
1335		http.Error(w, "Invalid network name", http.StatusBadRequest)
1336		return
1337	}
1338	if n, _, _ := s.findNetwork(config.Name); n != nil {
1339		http.Error(w, "network already exists", http.StatusForbidden)
1340		return
1341	}
1342
1343	generatedID := s.generateID()
1344	network := docker.Network{
1345		Name:       config.Name,
1346		ID:         generatedID,
1347		Driver:     config.Driver,
1348		Containers: map[string]docker.Endpoint{},
1349	}
1350	s.netMut.Lock()
1351	s.networks = append(s.networks, &network)
1352	s.netMut.Unlock()
1353	w.WriteHeader(http.StatusCreated)
1354	var c = struct{ ID string }{ID: network.ID}
1355	json.NewEncoder(w).Encode(c)
1356}
1357
1358func (s *DockerServer) removeNetwork(w http.ResponseWriter, r *http.Request) {
1359	id := mux.Vars(r)["id"]
1360	_, index, err := s.findNetwork(id)
1361	if err != nil {
1362		http.Error(w, err.Error(), http.StatusNotFound)
1363		return
1364	}
1365	s.netMut.Lock()
1366	defer s.netMut.Unlock()
1367	s.networks[index] = s.networks[len(s.networks)-1]
1368	s.networks = s.networks[:len(s.networks)-1]
1369	w.WriteHeader(http.StatusNoContent)
1370}
1371
1372func (s *DockerServer) networksConnect(w http.ResponseWriter, r *http.Request) {
1373	id := mux.Vars(r)["id"]
1374	var config *docker.NetworkConnectionOptions
1375	defer r.Body.Close()
1376	err := json.NewDecoder(r.Body).Decode(&config)
1377	if err != nil {
1378		http.Error(w, err.Error(), http.StatusBadRequest)
1379		return
1380	}
1381
1382	network, index, _ := s.findNetwork(id)
1383	container, _ := s.findContainer(config.Container)
1384	if network == nil || container == nil {
1385		http.Error(w, "network or container not found", http.StatusNotFound)
1386		return
1387	}
1388
1389	if _, found := network.Containers[container.ID]; found == true {
1390		http.Error(w, "endpoint already exists in network", http.StatusBadRequest)
1391		return
1392	}
1393
1394	s.netMut.Lock()
1395	s.networks[index].Containers[config.Container] = docker.Endpoint{}
1396	s.netMut.Unlock()
1397
1398	w.WriteHeader(http.StatusOK)
1399}
1400
1401func (s *DockerServer) listVolumes(w http.ResponseWriter, r *http.Request) {
1402	s.volMut.RLock()
1403	result := make([]docker.Volume, 0, len(s.volStore))
1404	for _, volumeCounter := range s.volStore {
1405		result = append(result, volumeCounter.volume)
1406	}
1407	s.volMut.RUnlock()
1408	w.Header().Set("Content-Type", "application/json")
1409	w.WriteHeader(http.StatusOK)
1410	json.NewEncoder(w).Encode(map[string][]docker.Volume{"Volumes": result})
1411}
1412
1413func (s *DockerServer) createVolume(w http.ResponseWriter, r *http.Request) {
1414	var data struct {
1415		*docker.CreateVolumeOptions
1416	}
1417	defer r.Body.Close()
1418	err := json.NewDecoder(r.Body).Decode(&data)
1419	if err != nil {
1420		http.Error(w, err.Error(), http.StatusBadRequest)
1421		return
1422	}
1423	volume := &docker.Volume{
1424		Name:   data.CreateVolumeOptions.Name,
1425		Driver: data.CreateVolumeOptions.Driver,
1426	}
1427	// If the name is not specified, generate one.  Just using generateID for now
1428	if len(volume.Name) == 0 {
1429		volume.Name = s.generateID()
1430	}
1431	// If driver is not specified, use local
1432	if len(volume.Driver) == 0 {
1433		volume.Driver = "local"
1434	}
1435	// Mount point is a default one with name
1436	volume.Mountpoint = "/var/lib/docker/volumes/" + volume.Name
1437
1438	// If the volume already exists, don't re-add it.
1439	exists := false
1440	s.volMut.Lock()
1441	if s.volStore != nil {
1442		_, exists = s.volStore[volume.Name]
1443	} else {
1444		// No volumes, create volStore
1445		s.volStore = make(map[string]*volumeCounter)
1446	}
1447	if !exists {
1448		s.volStore[volume.Name] = &volumeCounter{
1449			volume: *volume,
1450			count:  0,
1451		}
1452	}
1453	s.volMut.Unlock()
1454	w.WriteHeader(http.StatusCreated)
1455	json.NewEncoder(w).Encode(volume)
1456}
1457
1458func (s *DockerServer) inspectVolume(w http.ResponseWriter, r *http.Request) {
1459	s.volMut.RLock()
1460	defer s.volMut.RUnlock()
1461	name := mux.Vars(r)["name"]
1462	vol, err := s.findVolume(name)
1463	if err != nil {
1464		http.Error(w, err.Error(), http.StatusNotFound)
1465		return
1466	}
1467	w.Header().Set("Content-Type", "application/json")
1468	w.WriteHeader(http.StatusOK)
1469	json.NewEncoder(w).Encode(vol.volume)
1470}
1471
1472func (s *DockerServer) findVolume(name string) (*volumeCounter, error) {
1473	vol, ok := s.volStore[name]
1474	if !ok {
1475		return nil, errors.New("no such volume")
1476	}
1477	return vol, nil
1478}
1479
1480func (s *DockerServer) removeVolume(w http.ResponseWriter, r *http.Request) {
1481	s.volMut.Lock()
1482	defer s.volMut.Unlock()
1483	name := mux.Vars(r)["name"]
1484	vol, err := s.findVolume(name)
1485	if err != nil {
1486		http.Error(w, err.Error(), http.StatusNotFound)
1487		return
1488	}
1489	if vol.count != 0 {
1490		http.Error(w, "volume in use and cannot be removed", http.StatusConflict)
1491		return
1492	}
1493	delete(s.volStore, vol.volume.Name)
1494	w.WriteHeader(http.StatusNoContent)
1495}
1496
1497func (s *DockerServer) infoDocker(w http.ResponseWriter, r *http.Request) {
1498	s.cMut.RLock()
1499	defer s.cMut.RUnlock()
1500	s.iMut.RLock()
1501	defer s.iMut.RUnlock()
1502	var running, stopped, paused int
1503	for _, c := range s.containers {
1504		if c.State.Running {
1505			running++
1506		} else {
1507			stopped++
1508		}
1509		if c.State.Paused {
1510			paused++
1511		}
1512	}
1513	var swarmInfo *swarm.Info
1514	if s.swarm != nil {
1515		swarmInfo = &swarm.Info{
1516			NodeID: s.nodeID,
1517		}
1518		for _, n := range s.nodes {
1519			swarmInfo.RemoteManagers = append(swarmInfo.RemoteManagers, swarm.Peer{
1520				NodeID: n.ID,
1521				Addr:   n.ManagerStatus.Addr,
1522			})
1523		}
1524	}
1525	envs := map[string]interface{}{
1526		"ID":                "AAAA:XXXX:0000:BBBB:AAAA:XXXX:0000:BBBB:AAAA:XXXX:0000:BBBB",
1527		"Containers":        len(s.containers),
1528		"ContainersRunning": running,
1529		"ContainersPaused":  paused,
1530		"ContainersStopped": stopped,
1531		"Images":            len(s.images),
1532		"Driver":            "aufs",
1533		"DriverStatus":      [][]string{},
1534		"SystemStatus":      nil,
1535		"Plugins": map[string]interface{}{
1536			"Volume": []string{
1537				"local",
1538			},
1539			"Network": []string{
1540				"bridge",
1541				"null",
1542				"host",
1543			},
1544			"Authorization": nil,
1545		},
1546		"MemoryLimit":        true,
1547		"SwapLimit":          false,
1548		"CpuCfsPeriod":       true,
1549		"CpuCfsQuota":        true,
1550		"CPUShares":          true,
1551		"CPUSet":             true,
1552		"IPv4Forwarding":     true,
1553		"BridgeNfIptables":   true,
1554		"BridgeNfIp6tables":  true,
1555		"Debug":              false,
1556		"NFd":                79,
1557		"OomKillDisable":     true,
1558		"NGoroutines":        101,
1559		"SystemTime":         "2016-02-25T18:13:10.25870078Z",
1560		"ExecutionDriver":    "native-0.2",
1561		"LoggingDriver":      "json-file",
1562		"NEventsListener":    0,
1563		"KernelVersion":      "3.13.0-77-generic",
1564		"OperatingSystem":    "Ubuntu 14.04.3 LTS",
1565		"OSType":             "linux",
1566		"Architecture":       "x86_64",
1567		"IndexServerAddress": "https://index.docker.io/v1/",
1568		"RegistryConfig": map[string]interface{}{
1569			"InsecureRegistryCIDRs": []string{},
1570			"IndexConfigs":          map[string]interface{}{},
1571			"Mirrors":               nil,
1572		},
1573		"InitSha1":          "e2042dbb0fcf49bb9da199186d9a5063cda92a01",
1574		"InitPath":          "/usr/lib/docker/dockerinit",
1575		"NCPU":              1,
1576		"MemTotal":          2099204096,
1577		"DockerRootDir":     "/var/lib/docker",
1578		"HttpProxy":         "",
1579		"HttpsProxy":        "",
1580		"NoProxy":           "",
1581		"Name":              "vagrant-ubuntu-trusty-64",
1582		"Labels":            nil,
1583		"ExperimentalBuild": false,
1584		"ServerVersion":     "1.10.1",
1585		"ClusterStore":      "",
1586		"ClusterAdvertise":  "",
1587		"Swarm":             swarmInfo,
1588	}
1589	w.WriteHeader(http.StatusOK)
1590	json.NewEncoder(w).Encode(envs)
1591}
1592
1593func (s *DockerServer) versionDocker(w http.ResponseWriter, r *http.Request) {
1594	envs := map[string]interface{}{
1595		"Version":       "1.10.1",
1596		"Os":            "linux",
1597		"KernelVersion": "3.13.0-77-generic",
1598		"GoVersion":     "go1.4.2",
1599		"GitCommit":     "9e83765",
1600		"Arch":          "amd64",
1601		"ApiVersion":    "1.22",
1602		"BuildTime":     "2015-12-01T07:09:13.444803460+00:00",
1603		"Experimental":  false,
1604	}
1605	w.WriteHeader(http.StatusOK)
1606	json.NewEncoder(w).Encode(envs)
1607}
1608
1609// SwarmAddress returns the address if there's a fake swarm server enabled.
1610func (s *DockerServer) SwarmAddress() string {
1611	if s.swarmServer == nil {
1612		return ""
1613	}
1614	return s.swarmServer.listener.Addr().String()
1615}
1616
1617func (s *DockerServer) initSwarmNode(listenAddr, advertiseAddr string) (swarm.Node, error) {
1618	_, portPart, _ := net.SplitHostPort(listenAddr)
1619	if portPart == "" {
1620		portPart = "0"
1621	}
1622	var err error
1623	s.swarmServer, err = newSwarmServer(s, fmt.Sprintf("127.0.0.1:%s", portPart))
1624	if err != nil {
1625		return swarm.Node{}, err
1626	}
1627	if advertiseAddr == "" {
1628		advertiseAddr = s.SwarmAddress()
1629	}
1630	hostPart, portPart, err := net.SplitHostPort(advertiseAddr)
1631	if err != nil {
1632		hostPart = advertiseAddr
1633	}
1634	if portPart == "" || portPart == "0" {
1635		_, portPart, _ = net.SplitHostPort(s.SwarmAddress())
1636	}
1637	s.nodeID = s.generateID()
1638	return swarm.Node{
1639		ID: s.nodeID,
1640		Status: swarm.NodeStatus{
1641			Addr:  hostPart,
1642			State: swarm.NodeStateReady,
1643		},
1644		ManagerStatus: &swarm.ManagerStatus{
1645			Addr: fmt.Sprintf("%s:%s", hostPart, portPart),
1646		},
1647	}, nil
1648}
1649