Add context.RequestID to event stream
This PR adds a "request ID" to each event generated, the 'docker events' stream now looks like this: ``` 2015-09-10T15:02:50.000000000-07:00 [reqid: c01e3534ddca] de7c5d4ca927253cf4e978ee9c4545161e406e9b5a14617efb52c658b249174a: (from ubuntu) create ``` Note the `[reqID: c01e3534ddca]` part, that's new. Each HTTP request will generate its own unique ID. So, if you do a `docker build` you'll see a series of events all with the same reqID. This allow for log processing tools to determine which events are all related to the same http request. I didn't propigate the context to all possible funcs in the daemon, I decided to just do the ones that needed it in order to get the reqID into the events. I'd like to have people review this direction first, and if we're ok with it then I'll make sure we're consistent about when we pass around the context - IOW, make sure that all funcs at the same level have a context passed in even if they don't call the log funcs - this will ensure we're consistent w/o passing it around for all calls unnecessarily. ping @icecrime @calavera @crosbymichael Signed-off-by: Doug Davis <dug@us.ibm.com>
This commit is contained in:
parent
23750fb802
commit
26b1064967
68 changed files with 737 additions and 565 deletions
|
@ -45,7 +45,7 @@ func (s *Server) getContainersJSON(ctx context.Context, w http.ResponseWriter, r
|
|||
config.Limit = limit
|
||||
}
|
||||
|
||||
containers, err := s.daemon.Containers(config)
|
||||
containers, err := s.daemon.Containers(ctx, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ func (s *Server) getContainersStats(ctx context.Context, w http.ResponseWriter,
|
|||
Version: version,
|
||||
}
|
||||
|
||||
return s.daemon.ContainerStats(vars["name"], config)
|
||||
return s.daemon.ContainerStats(ctx, vars["name"], config)
|
||||
}
|
||||
|
||||
func (s *Server) getContainersLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -118,7 +118,7 @@ func (s *Server) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
|
|||
closeNotifier = notifier.CloseNotify()
|
||||
}
|
||||
|
||||
c, err := s.daemon.Get(vars["name"])
|
||||
c, err := s.daemon.Get(ctx, vars["name"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ func (s *Server) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
|
|||
Stop: closeNotifier,
|
||||
}
|
||||
|
||||
if err := s.daemon.ContainerLogs(c, logsConfig); err != nil {
|
||||
if err := s.daemon.ContainerLogs(ctx, c, logsConfig); err != nil {
|
||||
// The client may be expecting all of the data we're sending to
|
||||
// be multiplexed, so send it through OutStream, which will
|
||||
// have been set up to handle that if needed.
|
||||
|
@ -155,7 +155,7 @@ func (s *Server) getContainersExport(ctx context.Context, w http.ResponseWriter,
|
|||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
||||
return s.daemon.ContainerExport(vars["name"], w)
|
||||
return s.daemon.ContainerExport(ctx, vars["name"], w)
|
||||
}
|
||||
|
||||
func (s *Server) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -183,7 +183,7 @@ func (s *Server) postContainersStart(ctx context.Context, w http.ResponseWriter,
|
|||
hostConfig = c
|
||||
}
|
||||
|
||||
if err := s.daemon.ContainerStart(vars["name"], hostConfig); err != nil {
|
||||
if err := s.daemon.ContainerStart(ctx, vars["name"], hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
|
@ -200,7 +200,7 @@ func (s *Server) postContainersStop(ctx context.Context, w http.ResponseWriter,
|
|||
|
||||
seconds, _ := strconv.Atoi(r.Form.Get("t"))
|
||||
|
||||
if err := s.daemon.ContainerStop(vars["name"], seconds); err != nil {
|
||||
if err := s.daemon.ContainerStop(ctx, vars["name"], seconds); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
|
@ -227,7 +227,7 @@ func (s *Server) postContainersKill(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
}
|
||||
|
||||
if err := s.daemon.ContainerKill(name, uint64(sig)); err != nil {
|
||||
if err := s.daemon.ContainerKill(ctx, name, uint64(sig)); err != nil {
|
||||
theErr, isDerr := err.(errcode.ErrorCoder)
|
||||
isStopped := isDerr && theErr.ErrorCode() == derr.ErrorCodeNotRunning
|
||||
|
||||
|
@ -254,7 +254,7 @@ func (s *Server) postContainersRestart(ctx context.Context, w http.ResponseWrite
|
|||
|
||||
timeout, _ := strconv.Atoi(r.Form.Get("t"))
|
||||
|
||||
if err := s.daemon.ContainerRestart(vars["name"], timeout); err != nil {
|
||||
if err := s.daemon.ContainerRestart(ctx, vars["name"], timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -271,7 +271,7 @@ func (s *Server) postContainersPause(ctx context.Context, w http.ResponseWriter,
|
|||
return err
|
||||
}
|
||||
|
||||
if err := s.daemon.ContainerPause(vars["name"]); err != nil {
|
||||
if err := s.daemon.ContainerPause(ctx, vars["name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -288,7 +288,7 @@ func (s *Server) postContainersUnpause(ctx context.Context, w http.ResponseWrite
|
|||
return err
|
||||
}
|
||||
|
||||
if err := s.daemon.ContainerUnpause(vars["name"]); err != nil {
|
||||
if err := s.daemon.ContainerUnpause(ctx, vars["name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -302,7 +302,7 @@ func (s *Server) postContainersWait(ctx context.Context, w http.ResponseWriter,
|
|||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
||||
status, err := s.daemon.ContainerWait(vars["name"], -1*time.Second)
|
||||
status, err := s.daemon.ContainerWait(ctx, vars["name"], -1*time.Second)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ func (s *Server) getContainersChanges(ctx context.Context, w http.ResponseWriter
|
|||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
||||
changes, err := s.daemon.ContainerChanges(vars["name"])
|
||||
changes, err := s.daemon.ContainerChanges(ctx, vars["name"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -334,7 +334,7 @@ func (s *Server) getContainersTop(ctx context.Context, w http.ResponseWriter, r
|
|||
return err
|
||||
}
|
||||
|
||||
procList, err := s.daemon.ContainerTop(vars["name"], r.Form.Get("ps_args"))
|
||||
procList, err := s.daemon.ContainerTop(ctx, vars["name"], r.Form.Get("ps_args"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -352,7 +352,7 @@ func (s *Server) postContainerRename(ctx context.Context, w http.ResponseWriter,
|
|||
|
||||
name := vars["name"]
|
||||
newName := r.Form.Get("name")
|
||||
if err := s.daemon.ContainerRename(name, newName); err != nil {
|
||||
if err := s.daemon.ContainerRename(ctx, name, newName); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
|
@ -378,7 +378,7 @@ func (s *Server) postContainersCreate(ctx context.Context, w http.ResponseWriter
|
|||
version := ctx.Version()
|
||||
adjustCPUShares := version.LessThan("1.19")
|
||||
|
||||
container, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig, adjustCPUShares)
|
||||
container, warnings, err := s.daemon.ContainerCreate(ctx, name, config, hostConfig, adjustCPUShares)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -404,7 +404,7 @@ func (s *Server) deleteContainers(ctx context.Context, w http.ResponseWriter, r
|
|||
RemoveLink: boolValue(r, "link"),
|
||||
}
|
||||
|
||||
if err := s.daemon.ContainerRm(name, config); err != nil {
|
||||
if err := s.daemon.ContainerRm(ctx, name, config); err != nil {
|
||||
// Force a 404 for the empty string
|
||||
if strings.Contains(strings.ToLower(err.Error()), "prefix can't be empty") {
|
||||
return fmt.Errorf("no such id: \"\"")
|
||||
|
@ -434,7 +434,7 @@ func (s *Server) postContainersResize(ctx context.Context, w http.ResponseWriter
|
|||
return err
|
||||
}
|
||||
|
||||
return s.daemon.ContainerResize(vars["name"], height, width)
|
||||
return s.daemon.ContainerResize(ctx, vars["name"], height, width)
|
||||
}
|
||||
|
||||
func (s *Server) postContainersAttach(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -446,7 +446,7 @@ func (s *Server) postContainersAttach(ctx context.Context, w http.ResponseWriter
|
|||
}
|
||||
containerName := vars["name"]
|
||||
|
||||
if !s.daemon.Exists(containerName) {
|
||||
if !s.daemon.Exists(ctx, containerName) {
|
||||
return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
|
||||
}
|
||||
|
||||
|
@ -472,7 +472,7 @@ func (s *Server) postContainersAttach(ctx context.Context, w http.ResponseWriter
|
|||
Stream: boolValue(r, "stream"),
|
||||
}
|
||||
|
||||
if err := s.daemon.ContainerAttachWithLogs(containerName, attachWithLogsConfig); err != nil {
|
||||
if err := s.daemon.ContainerAttachWithLogs(ctx, containerName, attachWithLogsConfig); err != nil {
|
||||
fmt.Fprintf(outStream, "Error attaching: %s\n", err)
|
||||
}
|
||||
|
||||
|
@ -488,7 +488,7 @@ func (s *Server) wsContainersAttach(ctx context.Context, w http.ResponseWriter,
|
|||
}
|
||||
containerName := vars["name"]
|
||||
|
||||
if !s.daemon.Exists(containerName) {
|
||||
if !s.daemon.Exists(ctx, containerName) {
|
||||
return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
|
||||
}
|
||||
|
||||
|
@ -503,7 +503,7 @@ func (s *Server) wsContainersAttach(ctx context.Context, w http.ResponseWriter,
|
|||
Stream: boolValue(r, "stream"),
|
||||
}
|
||||
|
||||
if err := s.daemon.ContainerWsAttachWithLogs(containerName, wsAttachWithLogsConfig); err != nil {
|
||||
if err := s.daemon.ContainerWsAttachWithLogs(ctx, containerName, wsAttachWithLogsConfig); err != nil {
|
||||
logrus.Errorf("Error attaching websocket: %s", err)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -32,7 +32,7 @@ func (s *Server) postContainersCopy(ctx context.Context, w http.ResponseWriter,
|
|||
return fmt.Errorf("Path cannot be empty")
|
||||
}
|
||||
|
||||
data, err := s.daemon.ContainerCopy(vars["name"], cfg.Resource)
|
||||
data, err := s.daemon.ContainerCopy(ctx, vars["name"], cfg.Resource)
|
||||
if err != nil {
|
||||
if strings.Contains(strings.ToLower(err.Error()), "no such id") {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
|
@ -74,7 +74,7 @@ func (s *Server) headContainersArchive(ctx context.Context, w http.ResponseWrite
|
|||
return err
|
||||
}
|
||||
|
||||
stat, err := s.daemon.ContainerStatPath(v.name, v.path)
|
||||
stat, err := s.daemon.ContainerStatPath(ctx, v.name, v.path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ func (s *Server) getContainersArchive(ctx context.Context, w http.ResponseWriter
|
|||
return err
|
||||
}
|
||||
|
||||
tarArchive, stat, err := s.daemon.ContainerArchivePath(v.name, v.path)
|
||||
tarArchive, stat, err := s.daemon.ContainerArchivePath(ctx, v.name, v.path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -111,5 +111,5 @@ func (s *Server) putContainersArchive(ctx context.Context, w http.ResponseWriter
|
|||
}
|
||||
|
||||
noOverwriteDirNonDir := boolValue(r, "noOverwriteDirNonDir")
|
||||
return s.daemon.ContainerExtractToDir(v.name, v.path, noOverwriteDirNonDir, r.Body)
|
||||
return s.daemon.ContainerExtractToDir(ctx, v.name, v.path, noOverwriteDirNonDir, r.Body)
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ func (s *Server) getVersion(ctx context.Context, w http.ResponseWriter, r *http.
|
|||
}
|
||||
|
||||
func (s *Server) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
info, err := s.daemon.SystemInfo()
|
||||
info, err := s.daemon.SystemInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ func (s *Server) getEvents(ctx context.Context, w http.ResponseWriter, r *http.R
|
|||
enc := json.NewEncoder(outStream)
|
||||
|
||||
getContainerID := func(cn string) string {
|
||||
c, err := d.Get(cn)
|
||||
c, err := d.Get(ctx, cn)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ func (s *Server) getExecByID(ctx context.Context, w http.ResponseWriter, r *http
|
|||
return fmt.Errorf("Missing parameter 'id'")
|
||||
}
|
||||
|
||||
eConfig, err := s.daemon.ContainerExecInspect(vars["id"])
|
||||
eConfig, err := s.daemon.ContainerExecInspect(ctx, vars["id"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ func (s *Server) postContainerExecCreate(ctx context.Context, w http.ResponseWri
|
|||
}
|
||||
|
||||
// Register an instance of Exec in container.
|
||||
id, err := s.daemon.ContainerExecCreate(execConfig)
|
||||
id, err := s.daemon.ContainerExecCreate(ctx, execConfig)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error setting up exec command in container %s: %s", name, err)
|
||||
return err
|
||||
|
@ -100,7 +100,7 @@ func (s *Server) postContainerExecStart(ctx context.Context, w http.ResponseWrit
|
|||
}
|
||||
|
||||
// Now run the user process in container.
|
||||
if err := s.daemon.ContainerExecStart(execName, stdin, stdout, stderr); err != nil {
|
||||
if err := s.daemon.ContainerExecStart(ctx, execName, stdin, stdout, stderr); err != nil {
|
||||
fmt.Fprintf(outStream, "Error running exec in container: %v\n", err)
|
||||
}
|
||||
return nil
|
||||
|
@ -123,5 +123,5 @@ func (s *Server) postContainerExecResize(ctx context.Context, w http.ResponseWri
|
|||
return err
|
||||
}
|
||||
|
||||
return s.daemon.ContainerExecResize(vars["name"], height, width)
|
||||
return s.daemon.ContainerExecResize(ctx, vars["name"], height, width)
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ func (s *Server) postCommit(ctx context.Context, w http.ResponseWriter, r *http.
|
|||
Config: c,
|
||||
}
|
||||
|
||||
imgID, err := builder.Commit(cname, s.daemon, commitCfg)
|
||||
imgID, err := builder.Commit(ctx, cname, s.daemon, commitCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ func (s *Server) postImagesCreate(ctx context.Context, w http.ResponseWriter, r
|
|||
OutStream: output,
|
||||
}
|
||||
|
||||
err = s.daemon.Repositories().Pull(image, tag, imagePullConfig)
|
||||
err = s.daemon.Repositories(ctx).Pull(ctx, image, tag, imagePullConfig)
|
||||
} else { //import
|
||||
if tag == "" {
|
||||
repo, tag = parsers.ParseRepositoryTag(repo)
|
||||
|
@ -124,12 +124,12 @@ func (s *Server) postImagesCreate(ctx context.Context, w http.ResponseWriter, r
|
|||
// generated from the download to be available to the output
|
||||
// stream processing below
|
||||
var newConfig *runconfig.Config
|
||||
newConfig, err = builder.BuildFromConfig(s.daemon, &runconfig.Config{}, r.Form["changes"])
|
||||
newConfig, err = builder.BuildFromConfig(ctx, s.daemon, &runconfig.Config{}, r.Form["changes"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.daemon.Repositories().Import(src, repo, tag, message, r.Body, output, newConfig)
|
||||
err = s.daemon.Repositories(ctx).Import(ctx, src, repo, tag, message, r.Body, output, newConfig)
|
||||
}
|
||||
if err != nil {
|
||||
if !output.Flushed() {
|
||||
|
@ -184,7 +184,7 @@ func (s *Server) postImagesPush(ctx context.Context, w http.ResponseWriter, r *h
|
|||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if err := s.daemon.Repositories().Push(name, imagePushConfig); err != nil {
|
||||
if err := s.daemon.Repositories(ctx).Push(ctx, name, imagePushConfig); err != nil {
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ func (s *Server) getImagesGet(ctx context.Context, w http.ResponseWriter, r *htt
|
|||
names = r.Form["names"]
|
||||
}
|
||||
|
||||
if err := s.daemon.Repositories().ImageExport(names, output); err != nil {
|
||||
if err := s.daemon.Repositories(ctx).ImageExport(names, output); err != nil {
|
||||
if !output.Flushed() {
|
||||
return err
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ func (s *Server) getImagesGet(ctx context.Context, w http.ResponseWriter, r *htt
|
|||
}
|
||||
|
||||
func (s *Server) postImagesLoad(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
return s.daemon.Repositories().Load(r.Body, w)
|
||||
return s.daemon.Repositories(ctx).Load(r.Body, w)
|
||||
}
|
||||
|
||||
func (s *Server) deleteImages(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -243,7 +243,7 @@ func (s *Server) deleteImages(ctx context.Context, w http.ResponseWriter, r *htt
|
|||
force := boolValue(r, "force")
|
||||
prune := !boolValue(r, "noprune")
|
||||
|
||||
list, err := s.daemon.ImageDelete(name, force, prune)
|
||||
list, err := s.daemon.ImageDelete(ctx, name, force, prune)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ func (s *Server) getImagesByName(ctx context.Context, w http.ResponseWriter, r *
|
|||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
||||
imageInspect, err := s.daemon.Repositories().Lookup(vars["name"])
|
||||
imageInspect, err := s.daemon.Repositories(ctx).Lookup(vars["name"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -346,7 +346,7 @@ func (s *Server) postBuild(ctx context.Context, w http.ResponseWriter, r *http.R
|
|||
}()
|
||||
}
|
||||
|
||||
if err := builder.Build(s.daemon, buildConfig); err != nil {
|
||||
if err := builder.Build(ctx, s.daemon, buildConfig); err != nil {
|
||||
// Do not write the error in the http output if it's still empty.
|
||||
// This prevents from writing a 200(OK) when there is an interal error.
|
||||
if !output.Flushed() {
|
||||
|
@ -364,7 +364,7 @@ func (s *Server) getImagesJSON(ctx context.Context, w http.ResponseWriter, r *ht
|
|||
}
|
||||
|
||||
// FIXME: The filter parameter could just be a match filter
|
||||
images, err := s.daemon.Repositories().Images(r.Form.Get("filters"), r.Form.Get("filter"), boolValue(r, "all"))
|
||||
images, err := s.daemon.Repositories(ctx).Images(r.Form.Get("filters"), r.Form.Get("filter"), boolValue(r, "all"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -378,7 +378,7 @@ func (s *Server) getImagesHistory(ctx context.Context, w http.ResponseWriter, r
|
|||
}
|
||||
|
||||
name := vars["name"]
|
||||
history, err := s.daemon.Repositories().History(name)
|
||||
history, err := s.daemon.Repositories(ctx).History(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -398,10 +398,10 @@ func (s *Server) postImagesTag(ctx context.Context, w http.ResponseWriter, r *ht
|
|||
tag := r.Form.Get("tag")
|
||||
force := boolValue(r, "force")
|
||||
name := vars["name"]
|
||||
if err := s.daemon.Repositories().Tag(repo, tag, name, force); err != nil {
|
||||
if err := s.daemon.Repositories(ctx).Tag(repo, tag, name, force); err != nil {
|
||||
return err
|
||||
}
|
||||
s.daemon.EventsService.Log("tag", utils.ImageReference(repo, tag), "")
|
||||
s.daemon.EventsService.Log(ctx, "tag", utils.ImageReference(repo, tag), "")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@ func (s *Server) getContainersByName(ctx context.Context, w http.ResponseWriter,
|
|||
|
||||
switch {
|
||||
case version.LessThan("1.20"):
|
||||
json, err = s.daemon.ContainerInspectPre120(vars["name"])
|
||||
json, err = s.daemon.ContainerInspectPre120(ctx, vars["name"])
|
||||
case version.Equal("1.20"):
|
||||
json, err = s.daemon.ContainerInspect120(vars["name"])
|
||||
json, err = s.daemon.ContainerInspect120(ctx, vars["name"])
|
||||
default:
|
||||
json, err = s.daemon.ContainerInspect(vars["name"])
|
||||
json, err = s.daemon.ContainerInspect(ctx, vars["name"])
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/docker/pkg/sockets"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/utils"
|
||||
)
|
||||
|
||||
|
@ -41,12 +42,12 @@ type Server struct {
|
|||
}
|
||||
|
||||
// New returns a new instance of the server based on the specified configuration.
|
||||
func New(cfg *Config) *Server {
|
||||
func New(ctx context.Context, cfg *Config) *Server {
|
||||
srv := &Server{
|
||||
cfg: cfg,
|
||||
start: make(chan struct{}),
|
||||
}
|
||||
srv.router = createRouter(srv)
|
||||
srv.router = createRouter(ctx, srv)
|
||||
return srv
|
||||
}
|
||||
|
||||
|
@ -290,7 +291,7 @@ func (s *Server) initTCPSocket(addr string) (l net.Listener, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (s *Server) makeHTTPHandler(localMethod string, localRoute string, localHandler HTTPAPIFunc) http.HandlerFunc {
|
||||
func (s *Server) makeHTTPHandler(ctx context.Context, localMethod string, localRoute string, localHandler HTTPAPIFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// log the handler generation
|
||||
logrus.Debugf("Calling %s %s", localMethod, localRoute)
|
||||
|
@ -302,7 +303,8 @@ func (s *Server) makeHTTPHandler(localMethod string, localRoute string, localHan
|
|||
// apply to all requests. Data that is specific to the
|
||||
// immediate function being called should still be passed
|
||||
// as 'args' on the function call.
|
||||
ctx := context.Background()
|
||||
reqID := stringid.TruncateID(stringid.GenerateNonCryptoID())
|
||||
ctx = context.WithValue(ctx, context.RequestID, reqID)
|
||||
handlerFunc := s.handleWithGlobalMiddlewares(localHandler)
|
||||
|
||||
if err := handlerFunc(ctx, w, r, mux.Vars(r)); err != nil {
|
||||
|
@ -314,7 +316,7 @@ func (s *Server) makeHTTPHandler(localMethod string, localRoute string, localHan
|
|||
|
||||
// createRouter initializes the main router the server uses.
|
||||
// we keep enableCors just for legacy usage, need to be removed in the future
|
||||
func createRouter(s *Server) *mux.Router {
|
||||
func createRouter(ctx context.Context, s *Server) *mux.Router {
|
||||
r := mux.NewRouter()
|
||||
if os.Getenv("DEBUG") != "" {
|
||||
profilerSetup(r, "/debug/")
|
||||
|
@ -394,7 +396,7 @@ func createRouter(s *Server) *mux.Router {
|
|||
localMethod := method
|
||||
|
||||
// build the handler function
|
||||
f := s.makeHTTPHandler(localMethod, localRoute, localFct)
|
||||
f := s.makeHTTPHandler(ctx, localMethod, localRoute, localFct)
|
||||
|
||||
// add the new route
|
||||
if localRoute == "" {
|
||||
|
|
|
@ -2,8 +2,12 @@
|
|||
|
||||
package server
|
||||
|
||||
func (s *Server) registerSubRouter() {
|
||||
httpHandler := s.daemon.NetworkAPIRouter()
|
||||
import (
|
||||
"github.com/docker/docker/context"
|
||||
)
|
||||
|
||||
func (s *Server) registerSubRouter(ctx context.Context) {
|
||||
httpHandler := s.daemon.NetworkAPIRouter(ctx)
|
||||
|
||||
subrouter := s.router.PathPrefix("/v{version:[0-9.]+}/networks").Subrouter()
|
||||
subrouter.Methods("GET", "POST", "PUT", "DELETE").HandlerFunc(httpHandler)
|
||||
|
|
|
@ -2,5 +2,9 @@
|
|||
|
||||
package server
|
||||
|
||||
func (s *Server) registerSubRouter() {
|
||||
import (
|
||||
"github.com/docker/docker/context"
|
||||
)
|
||||
|
||||
func (s *Server) registerSubRouter(ctx context.Context) {
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/docker/pkg/sockets"
|
||||
"github.com/docker/libnetwork/portallocator"
|
||||
|
@ -63,10 +64,10 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
|
|||
// AcceptConnections allows clients to connect to the API server.
|
||||
// Referenced Daemon is notified about this server, and waits for the
|
||||
// daemon acknowledgement before the incoming connections are accepted.
|
||||
func (s *Server) AcceptConnections(d *daemon.Daemon) {
|
||||
func (s *Server) AcceptConnections(ctx context.Context, d *daemon.Daemon) {
|
||||
// Tell the init daemon we are accepting requests
|
||||
s.daemon = d
|
||||
s.registerSubRouter()
|
||||
s.registerSubRouter(ctx)
|
||||
go systemdDaemon.SdNotify("READY=1")
|
||||
// close the lock so the listeners start accepting connections
|
||||
select {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon"
|
||||
)
|
||||
|
||||
|
@ -42,9 +43,9 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
|
|||
}
|
||||
|
||||
// AcceptConnections allows router to start listening for the incoming requests.
|
||||
func (s *Server) AcceptConnections(d *daemon.Daemon) {
|
||||
func (s *Server) AcceptConnections(ctx context.Context, d *daemon.Daemon) {
|
||||
s.daemon = d
|
||||
s.registerSubRouter()
|
||||
s.registerSubRouter(ctx)
|
||||
// close the lock so the listeners start accepting connections
|
||||
select {
|
||||
case <-s.start:
|
||||
|
|
|
@ -13,7 +13,7 @@ func (s *Server) getVolumesList(ctx context.Context, w http.ResponseWriter, r *h
|
|||
return err
|
||||
}
|
||||
|
||||
volumes, err := s.daemon.Volumes(r.Form.Get("filters"))
|
||||
volumes, err := s.daemon.Volumes(ctx, r.Form.Get("filters"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ func (s *Server) getVolumeByName(ctx context.Context, w http.ResponseWriter, r *
|
|||
return err
|
||||
}
|
||||
|
||||
v, err := s.daemon.VolumeInspect(vars["name"])
|
||||
v, err := s.daemon.VolumeInspect(ctx, vars["name"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ func (s *Server) postVolumesCreate(ctx context.Context, w http.ResponseWriter, r
|
|||
return err
|
||||
}
|
||||
|
||||
volume, err := s.daemon.VolumeCreate(req.Name, req.Driver, req.DriverOpts)
|
||||
volume, err := s.daemon.VolumeCreate(ctx, req.Name, req.Driver, req.DriverOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ func (s *Server) deleteVolumes(ctx context.Context, w http.ResponseWriter, r *ht
|
|||
if err := parseForm(r); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.daemon.VolumeRm(vars["name"]); err != nil {
|
||||
if err := s.daemon.VolumeRm(ctx, vars["name"]); err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/context"
|
||||
derr "github.com/docker/docker/errors"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/nat"
|
||||
|
@ -43,7 +44,7 @@ func nullDispatch(b *builder, args []string, attributes map[string]bool, origina
|
|||
// Sets the environment variable foo to bar, also makes interpolation
|
||||
// in the dockerfile available from the next statement on via ${foo}.
|
||||
//
|
||||
func env(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func env(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if len(args) == 0 {
|
||||
return derr.ErrorCodeAtLeastOneArg.WithArgs("ENV")
|
||||
}
|
||||
|
@ -96,13 +97,13 @@ func env(b *builder, args []string, attributes map[string]bool, original string)
|
|||
j++
|
||||
}
|
||||
|
||||
return b.commit("", b.Config.Cmd, commitStr)
|
||||
return b.commit(ctx, "", b.Config.Cmd, commitStr)
|
||||
}
|
||||
|
||||
// MAINTAINER some text <maybe@an.email.address>
|
||||
//
|
||||
// Sets the maintainer metadata.
|
||||
func maintainer(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func maintainer(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if len(args) != 1 {
|
||||
return derr.ErrorCodeExactlyOneArg.WithArgs("MAINTAINER")
|
||||
}
|
||||
|
@ -112,14 +113,14 @@ func maintainer(b *builder, args []string, attributes map[string]bool, original
|
|||
}
|
||||
|
||||
b.maintainer = args[0]
|
||||
return b.commit("", b.Config.Cmd, fmt.Sprintf("MAINTAINER %s", b.maintainer))
|
||||
return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("MAINTAINER %s", b.maintainer))
|
||||
}
|
||||
|
||||
// LABEL some json data describing the image
|
||||
//
|
||||
// Sets the Label variable foo to bar,
|
||||
//
|
||||
func label(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func label(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if len(args) == 0 {
|
||||
return derr.ErrorCodeAtLeastOneArg.WithArgs("LABEL")
|
||||
}
|
||||
|
@ -147,7 +148,7 @@ func label(b *builder, args []string, attributes map[string]bool, original strin
|
|||
b.Config.Labels[args[j]] = args[j+1]
|
||||
j++
|
||||
}
|
||||
return b.commit("", b.Config.Cmd, commitStr)
|
||||
return b.commit(ctx, "", b.Config.Cmd, commitStr)
|
||||
}
|
||||
|
||||
// ADD foo /path
|
||||
|
@ -155,7 +156,7 @@ func label(b *builder, args []string, attributes map[string]bool, original strin
|
|||
// Add the file 'foo' to '/path'. Tarball and Remote URL (git, http) handling
|
||||
// exist here. If you do not wish to have this automatic handling, use COPY.
|
||||
//
|
||||
func add(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func add(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if len(args) < 2 {
|
||||
return derr.ErrorCodeAtLeastTwoArgs.WithArgs("ADD")
|
||||
}
|
||||
|
@ -164,14 +165,14 @@ func add(b *builder, args []string, attributes map[string]bool, original string)
|
|||
return err
|
||||
}
|
||||
|
||||
return b.runContextCommand(args, true, true, "ADD")
|
||||
return b.runContextCommand(ctx, args, true, true, "ADD")
|
||||
}
|
||||
|
||||
// COPY foo /path
|
||||
//
|
||||
// Same as 'ADD' but without the tar and remote url handling.
|
||||
//
|
||||
func dispatchCopy(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func dispatchCopy(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if len(args) < 2 {
|
||||
return derr.ErrorCodeAtLeastTwoArgs.WithArgs("COPY")
|
||||
}
|
||||
|
@ -180,14 +181,14 @@ func dispatchCopy(b *builder, args []string, attributes map[string]bool, origina
|
|||
return err
|
||||
}
|
||||
|
||||
return b.runContextCommand(args, false, false, "COPY")
|
||||
return b.runContextCommand(ctx, args, false, false, "COPY")
|
||||
}
|
||||
|
||||
// FROM imagename
|
||||
//
|
||||
// This sets the image the dockerfile will build on top of.
|
||||
//
|
||||
func from(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func from(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if len(args) != 1 {
|
||||
return derr.ErrorCodeExactlyOneArg.WithArgs("FROM")
|
||||
}
|
||||
|
@ -208,16 +209,16 @@ func from(b *builder, args []string, attributes map[string]bool, original string
|
|||
return nil
|
||||
}
|
||||
|
||||
image, err := b.Daemon.Repositories().LookupImage(name)
|
||||
image, err := b.Daemon.Repositories(ctx).LookupImage(name)
|
||||
if b.Pull {
|
||||
image, err = b.pullImage(name)
|
||||
image, err = b.pullImage(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if b.Daemon.Graph().IsNotExist(err, name) {
|
||||
image, err = b.pullImage(name)
|
||||
if b.Daemon.Graph(ctx).IsNotExist(err, name) {
|
||||
image, err = b.pullImage(ctx, name)
|
||||
}
|
||||
|
||||
// note that the top level err will still be !nil here if IsNotExist is
|
||||
|
@ -227,7 +228,7 @@ func from(b *builder, args []string, attributes map[string]bool, original string
|
|||
}
|
||||
}
|
||||
|
||||
return b.processImageFrom(image)
|
||||
return b.processImageFrom(ctx, image)
|
||||
}
|
||||
|
||||
// ONBUILD RUN echo yo
|
||||
|
@ -239,7 +240,7 @@ func from(b *builder, args []string, attributes map[string]bool, original string
|
|||
// special cases. search for 'OnBuild' in internals.go for additional special
|
||||
// cases.
|
||||
//
|
||||
func onbuild(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func onbuild(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if len(args) == 0 {
|
||||
return derr.ErrorCodeAtLeastOneArg.WithArgs("ONBUILD")
|
||||
}
|
||||
|
@ -259,14 +260,14 @@ func onbuild(b *builder, args []string, attributes map[string]bool, original str
|
|||
original = regexp.MustCompile(`(?i)^\s*ONBUILD\s*`).ReplaceAllString(original, "")
|
||||
|
||||
b.Config.OnBuild = append(b.Config.OnBuild, original)
|
||||
return b.commit("", b.Config.Cmd, fmt.Sprintf("ONBUILD %s", original))
|
||||
return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("ONBUILD %s", original))
|
||||
}
|
||||
|
||||
// WORKDIR /tmp
|
||||
//
|
||||
// Set the working directory for future RUN/CMD/etc statements.
|
||||
//
|
||||
func workdir(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func workdir(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if len(args) != 1 {
|
||||
return derr.ErrorCodeExactlyOneArg.WithArgs("WORKDIR")
|
||||
}
|
||||
|
@ -286,7 +287,7 @@ func workdir(b *builder, args []string, attributes map[string]bool, original str
|
|||
|
||||
b.Config.WorkingDir = workdir
|
||||
|
||||
return b.commit("", b.Config.Cmd, fmt.Sprintf("WORKDIR %v", workdir))
|
||||
return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("WORKDIR %v", workdir))
|
||||
}
|
||||
|
||||
// RUN some command yo
|
||||
|
@ -299,7 +300,7 @@ func workdir(b *builder, args []string, attributes map[string]bool, original str
|
|||
// RUN echo hi # cmd /S /C echo hi (Windows)
|
||||
// RUN [ "echo", "hi" ] # echo hi
|
||||
//
|
||||
func run(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func run(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if b.image == "" && !b.noBaseImage {
|
||||
return derr.ErrorCodeMissingFrom
|
||||
}
|
||||
|
@ -380,7 +381,7 @@ func run(b *builder, args []string, attributes map[string]bool, original string)
|
|||
}
|
||||
|
||||
b.Config.Cmd = saveCmd
|
||||
hit, err := b.probeCache()
|
||||
hit, err := b.probeCache(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -395,17 +396,17 @@ func run(b *builder, args []string, attributes map[string]bool, original string)
|
|||
|
||||
logrus.Debugf("[BUILDER] Command to be executed: %v", b.Config.Cmd)
|
||||
|
||||
c, err := b.create()
|
||||
c, err := b.create(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure that we keep the container mounted until the commit
|
||||
// to avoid unmounting and then mounting directly again
|
||||
c.Mount()
|
||||
defer c.Unmount()
|
||||
c.Mount(ctx)
|
||||
defer c.Unmount(ctx)
|
||||
|
||||
err = b.run(c)
|
||||
err = b.run(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -415,7 +416,7 @@ func run(b *builder, args []string, attributes map[string]bool, original string)
|
|||
// properly match it.
|
||||
b.Config.Env = env
|
||||
b.Config.Cmd = saveCmd
|
||||
if err := b.commit(c.ID, cmd, "run"); err != nil {
|
||||
if err := b.commit(ctx, c.ID, cmd, "run"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -427,7 +428,7 @@ func run(b *builder, args []string, attributes map[string]bool, original string)
|
|||
// Set the default command to run in the container (which may be empty).
|
||||
// Argument handling is the same as RUN.
|
||||
//
|
||||
func cmd(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func cmd(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if err := b.BuilderFlags.Parse(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -444,7 +445,7 @@ func cmd(b *builder, args []string, attributes map[string]bool, original string)
|
|||
|
||||
b.Config.Cmd = stringutils.NewStrSlice(cmdSlice...)
|
||||
|
||||
if err := b.commit("", b.Config.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil {
|
||||
if err := b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -463,7 +464,7 @@ func cmd(b *builder, args []string, attributes map[string]bool, original string)
|
|||
// Handles command processing similar to CMD and RUN, only b.Config.Entrypoint
|
||||
// is initialized at NewBuilder time instead of through argument parsing.
|
||||
//
|
||||
func entrypoint(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func entrypoint(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if err := b.BuilderFlags.Parse(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -492,7 +493,7 @@ func entrypoint(b *builder, args []string, attributes map[string]bool, original
|
|||
b.Config.Cmd = nil
|
||||
}
|
||||
|
||||
if err := b.commit("", b.Config.Cmd, fmt.Sprintf("ENTRYPOINT %q", b.Config.Entrypoint)); err != nil {
|
||||
if err := b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("ENTRYPOINT %q", b.Config.Entrypoint)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -504,7 +505,7 @@ func entrypoint(b *builder, args []string, attributes map[string]bool, original
|
|||
// Expose ports for links and port mappings. This all ends up in
|
||||
// b.Config.ExposedPorts for runconfig.
|
||||
//
|
||||
func expose(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func expose(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
portsTab := args
|
||||
|
||||
if len(args) == 0 {
|
||||
|
@ -537,7 +538,7 @@ func expose(b *builder, args []string, attributes map[string]bool, original stri
|
|||
i++
|
||||
}
|
||||
sort.Strings(portList)
|
||||
return b.commit("", b.Config.Cmd, fmt.Sprintf("EXPOSE %s", strings.Join(portList, " ")))
|
||||
return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("EXPOSE %s", strings.Join(portList, " ")))
|
||||
}
|
||||
|
||||
// USER foo
|
||||
|
@ -545,7 +546,7 @@ func expose(b *builder, args []string, attributes map[string]bool, original stri
|
|||
// Set the user to 'foo' for future commands and when running the
|
||||
// ENTRYPOINT/CMD at container run time.
|
||||
//
|
||||
func user(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func user(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if len(args) != 1 {
|
||||
return derr.ErrorCodeExactlyOneArg.WithArgs("USER")
|
||||
}
|
||||
|
@ -555,14 +556,14 @@ func user(b *builder, args []string, attributes map[string]bool, original string
|
|||
}
|
||||
|
||||
b.Config.User = args[0]
|
||||
return b.commit("", b.Config.Cmd, fmt.Sprintf("USER %v", args))
|
||||
return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("USER %v", args))
|
||||
}
|
||||
|
||||
// VOLUME /foo
|
||||
//
|
||||
// Expose the volume /foo for use. Will also accept the JSON array form.
|
||||
//
|
||||
func volume(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func volume(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if len(args) == 0 {
|
||||
return derr.ErrorCodeAtLeastOneArg.WithArgs("VOLUME")
|
||||
}
|
||||
|
@ -581,7 +582,7 @@ func volume(b *builder, args []string, attributes map[string]bool, original stri
|
|||
}
|
||||
b.Config.Volumes[v] = struct{}{}
|
||||
}
|
||||
if err := b.commit("", b.Config.Cmd, fmt.Sprintf("VOLUME %v", args)); err != nil {
|
||||
if err := b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("VOLUME %v", args)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -590,7 +591,7 @@ func volume(b *builder, args []string, attributes map[string]bool, original stri
|
|||
// STOPSIGNAL signal
|
||||
//
|
||||
// Set the signal that will be used to kill the container.
|
||||
func stopSignal(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func stopSignal(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if len(args) != 1 {
|
||||
return fmt.Errorf("STOPSIGNAL requires exactly one argument")
|
||||
}
|
||||
|
@ -602,7 +603,7 @@ func stopSignal(b *builder, args []string, attributes map[string]bool, original
|
|||
}
|
||||
|
||||
b.Config.StopSignal = sig
|
||||
return b.commit("", b.Config.Cmd, fmt.Sprintf("STOPSIGNAL %v", args))
|
||||
return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("STOPSIGNAL %v", args))
|
||||
}
|
||||
|
||||
// ARG name[=value]
|
||||
|
@ -610,7 +611,7 @@ func stopSignal(b *builder, args []string, attributes map[string]bool, original
|
|||
// Adds the variable foo to the trusted list of variables that can be passed
|
||||
// to builder using the --build-arg flag for expansion/subsitution or passing to 'run'.
|
||||
// Dockerfile author may optionally set a default value of this variable.
|
||||
func arg(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
func arg(ctx context.Context, b *builder, args []string, attributes map[string]bool, original string) error {
|
||||
if len(args) != 1 {
|
||||
return fmt.Errorf("ARG requires exactly one argument definition")
|
||||
}
|
||||
|
@ -646,5 +647,5 @@ func arg(b *builder, args []string, attributes map[string]bool, original string)
|
|||
b.buildArgs[name] = value
|
||||
}
|
||||
|
||||
return b.commit("", b.Config.Cmd, fmt.Sprintf("ARG %s", arg))
|
||||
return b.commit(ctx, "", b.Config.Cmd, fmt.Sprintf("ARG %s", arg))
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
"github.com/docker/docker/builder/command"
|
||||
"github.com/docker/docker/builder/parser"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/docker/pkg/fileutils"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
|
@ -57,10 +58,10 @@ var replaceEnvAllowed = map[string]struct{}{
|
|||
command.Arg: {},
|
||||
}
|
||||
|
||||
var evaluateTable map[string]func(*builder, []string, map[string]bool, string) error
|
||||
var evaluateTable map[string]func(context.Context, *builder, []string, map[string]bool, string) error
|
||||
|
||||
func init() {
|
||||
evaluateTable = map[string]func(*builder, []string, map[string]bool, string) error{
|
||||
evaluateTable = map[string]func(context.Context, *builder, []string, map[string]bool, string) error{
|
||||
command.Env: env,
|
||||
command.Label: label,
|
||||
command.Maintainer: maintainer,
|
||||
|
@ -158,7 +159,7 @@ type builder struct {
|
|||
// processing.
|
||||
// * Print a happy message and return the image ID.
|
||||
//
|
||||
func (b *builder) Run(context io.Reader) (string, error) {
|
||||
func (b *builder) Run(ctx context.Context, context io.Reader) (string, error) {
|
||||
if err := b.readContext(context); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -187,15 +188,15 @@ func (b *builder) Run(context io.Reader) (string, error) {
|
|||
default:
|
||||
// Not cancelled yet, keep going...
|
||||
}
|
||||
if err := b.dispatch(i, n); err != nil {
|
||||
if err := b.dispatch(ctx, i, n); err != nil {
|
||||
if b.ForceRemove {
|
||||
b.clearTmp()
|
||||
b.clearTmp(ctx)
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
fmt.Fprintf(b.OutStream, " ---> %s\n", stringid.TruncateID(b.image))
|
||||
if b.Remove {
|
||||
b.clearTmp()
|
||||
b.clearTmp(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -311,7 +312,7 @@ func (b *builder) isBuildArgAllowed(arg string) bool {
|
|||
// such as `RUN` in ONBUILD RUN foo. There is special case logic in here to
|
||||
// deal with that, at least until it becomes more of a general concern with new
|
||||
// features.
|
||||
func (b *builder) dispatch(stepN int, ast *parser.Node) error {
|
||||
func (b *builder) dispatch(ctx context.Context, stepN int, ast *parser.Node) error {
|
||||
cmd := ast.Value
|
||||
|
||||
// To ensure the user is give a decent error message if the platform
|
||||
|
@ -404,7 +405,7 @@ func (b *builder) dispatch(stepN int, ast *parser.Node) error {
|
|||
if f, ok := evaluateTable[cmd]; ok {
|
||||
b.BuilderFlags = NewBFlags()
|
||||
b.BuilderFlags.Args = flags
|
||||
return f(b, strList, attrs, original)
|
||||
return f(ctx, b, strList, attrs, original)
|
||||
}
|
||||
|
||||
return fmt.Errorf("Unknown instruction: %s", strings.ToUpper(cmd))
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/builder/parser"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/docker/graph"
|
||||
"github.com/docker/docker/image"
|
||||
|
@ -75,7 +76,7 @@ func (b *builder) readContext(context io.Reader) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment string) error {
|
||||
func (b *builder) commit(ctx context.Context, id string, autoCmd *stringutils.StrSlice, comment string) error {
|
||||
if b.disableCommit {
|
||||
return nil
|
||||
}
|
||||
|
@ -92,7 +93,7 @@ func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment strin
|
|||
}
|
||||
defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)
|
||||
|
||||
hit, err := b.probeCache()
|
||||
hit, err := b.probeCache(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -100,18 +101,18 @@ func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment strin
|
|||
return nil
|
||||
}
|
||||
|
||||
container, err := b.create()
|
||||
container, err := b.create(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
id = container.ID
|
||||
|
||||
if err := container.Mount(); err != nil {
|
||||
if err := container.Mount(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
defer container.Unmount()
|
||||
defer container.Unmount(ctx)
|
||||
}
|
||||
container, err := b.Daemon.Get(id)
|
||||
container, err := b.Daemon.Get(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -127,11 +128,11 @@ func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment strin
|
|||
}
|
||||
|
||||
// Commit the container
|
||||
image, err := b.Daemon.Commit(container, commitCfg)
|
||||
image, err := b.Daemon.Commit(ctx, container, commitCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.Daemon.Graph().Retain(b.id, image.ID)
|
||||
b.Daemon.Graph(ctx).Retain(b.id, image.ID)
|
||||
b.activeImages = append(b.activeImages, image.ID)
|
||||
b.image = image.ID
|
||||
return nil
|
||||
|
@ -145,7 +146,7 @@ type copyInfo struct {
|
|||
tmpDir string
|
||||
}
|
||||
|
||||
func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecompression bool, cmdName string) error {
|
||||
func (b *builder) runContextCommand(ctx context.Context, args []string, allowRemote bool, allowDecompression bool, cmdName string) error {
|
||||
if b.context == nil {
|
||||
return fmt.Errorf("No context given. Impossible to use %s", cmdName)
|
||||
}
|
||||
|
@ -223,7 +224,7 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp
|
|||
}
|
||||
defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)
|
||||
|
||||
hit, err := b.probeCache()
|
||||
hit, err := b.probeCache(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -232,16 +233,16 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp
|
|||
return nil
|
||||
}
|
||||
|
||||
container, _, err := b.Daemon.ContainerCreate("", b.Config, nil, true)
|
||||
container, _, err := b.Daemon.ContainerCreate(ctx, "", b.Config, nil, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.TmpContainers[container.ID] = struct{}{}
|
||||
|
||||
if err := container.Mount(); err != nil {
|
||||
if err := container.Mount(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
defer container.Unmount()
|
||||
defer container.Unmount(ctx)
|
||||
|
||||
for _, ci := range copyInfos {
|
||||
if err := b.addContext(container, ci.origPath, ci.destPath, ci.decompress); err != nil {
|
||||
|
@ -249,7 +250,7 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp
|
|||
}
|
||||
}
|
||||
|
||||
if err := b.commit(container.ID, cmd, fmt.Sprintf("%s %s in %s", cmdName, origPaths, dest)); err != nil {
|
||||
if err := b.commit(ctx, container.ID, cmd, fmt.Sprintf("%s %s in %s", cmdName, origPaths, dest)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -484,7 +485,7 @@ func containsWildcards(name string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (b *builder) pullImage(name string) (*image.Image, error) {
|
||||
func (b *builder) pullImage(ctx context.Context, name string) (*image.Image, error) {
|
||||
remote, tag := parsers.ParseRepositoryTag(name)
|
||||
if tag == "" {
|
||||
tag = "latest"
|
||||
|
@ -510,11 +511,11 @@ func (b *builder) pullImage(name string) (*image.Image, error) {
|
|||
OutStream: ioutils.NopWriteCloser(b.OutOld),
|
||||
}
|
||||
|
||||
if err := b.Daemon.Repositories().Pull(remote, tag, imagePullConfig); err != nil {
|
||||
if err := b.Daemon.Repositories(ctx).Pull(ctx, remote, tag, imagePullConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
image, err := b.Daemon.Repositories().LookupImage(name)
|
||||
image, err := b.Daemon.Repositories(ctx).LookupImage(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -522,7 +523,7 @@ func (b *builder) pullImage(name string) (*image.Image, error) {
|
|||
return image, nil
|
||||
}
|
||||
|
||||
func (b *builder) processImageFrom(img *image.Image) error {
|
||||
func (b *builder) processImageFrom(ctx context.Context, img *image.Image) error {
|
||||
b.image = img.ID
|
||||
|
||||
if img.Config != nil {
|
||||
|
@ -562,7 +563,7 @@ func (b *builder) processImageFrom(img *image.Image) error {
|
|||
return fmt.Errorf("%s isn't allowed as an ONBUILD trigger", n.Value)
|
||||
}
|
||||
|
||||
if err := b.dispatch(i, n); err != nil {
|
||||
if err := b.dispatch(ctx, i, n); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -576,12 +577,12 @@ func (b *builder) processImageFrom(img *image.Image) error {
|
|||
// in the current server `b.Daemon`. If an image is found, probeCache returns
|
||||
// `(true, nil)`. If no image is found, it returns `(false, nil)`. If there
|
||||
// is any error, it returns `(false, err)`.
|
||||
func (b *builder) probeCache() (bool, error) {
|
||||
func (b *builder) probeCache(ctx context.Context) (bool, error) {
|
||||
if !b.UtilizeCache || b.cacheBusted {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
cache, err := b.Daemon.ImageGetCached(b.image, b.Config)
|
||||
cache, err := b.Daemon.ImageGetCached(ctx, b.image, b.Config)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -594,12 +595,12 @@ func (b *builder) probeCache() (bool, error) {
|
|||
fmt.Fprintf(b.OutStream, " ---> Using cache\n")
|
||||
logrus.Debugf("[BUILDER] Use cached version")
|
||||
b.image = cache.ID
|
||||
b.Daemon.Graph().Retain(b.id, cache.ID)
|
||||
b.Daemon.Graph(ctx).Retain(b.id, cache.ID)
|
||||
b.activeImages = append(b.activeImages, cache.ID)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (b *builder) create() (*daemon.Container, error) {
|
||||
func (b *builder) create(ctx context.Context) (*daemon.Container, error) {
|
||||
if b.image == "" && !b.noBaseImage {
|
||||
return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
|
||||
}
|
||||
|
@ -620,7 +621,7 @@ func (b *builder) create() (*daemon.Container, error) {
|
|||
config := *b.Config
|
||||
|
||||
// Create the container
|
||||
c, warnings, err := b.Daemon.ContainerCreate("", b.Config, hostConfig, true)
|
||||
c, warnings, err := b.Daemon.ContainerCreate(ctx, "", b.Config, hostConfig, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -643,14 +644,14 @@ func (b *builder) create() (*daemon.Container, error) {
|
|||
return c, nil
|
||||
}
|
||||
|
||||
func (b *builder) run(c *daemon.Container) error {
|
||||
func (b *builder) run(ctx context.Context, c *daemon.Container) error {
|
||||
var errCh chan error
|
||||
if b.Verbose {
|
||||
errCh = c.Attach(nil, b.OutStream, b.ErrStream)
|
||||
}
|
||||
|
||||
//start the container
|
||||
if err := c.Start(); err != nil {
|
||||
if err := c.Start(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -660,7 +661,7 @@ func (b *builder) run(c *daemon.Container) error {
|
|||
select {
|
||||
case <-b.cancelled:
|
||||
logrus.Debugln("Build cancelled, killing container:", c.ID)
|
||||
c.Kill()
|
||||
c.Kill(ctx)
|
||||
case <-finished:
|
||||
}
|
||||
}()
|
||||
|
@ -791,13 +792,13 @@ func copyAsDirectory(source, destination string, destExisted bool) error {
|
|||
return fixPermissions(source, destination, 0, 0, destExisted)
|
||||
}
|
||||
|
||||
func (b *builder) clearTmp() {
|
||||
func (b *builder) clearTmp(ctx context.Context) {
|
||||
for c := range b.TmpContainers {
|
||||
rmConfig := &daemon.ContainerRmConfig{
|
||||
ForceRemove: true,
|
||||
RemoveVolume: true,
|
||||
}
|
||||
if err := b.Daemon.ContainerRm(c, rmConfig); err != nil {
|
||||
if err := b.Daemon.ContainerRm(ctx, c, rmConfig); err != nil {
|
||||
fmt.Fprintf(b.OutStream, "Error removing intermediate container %s: %v\n", stringid.TruncateID(c), err)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/builder/parser"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/docker/graph/tags"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
|
@ -112,7 +113,7 @@ func NewBuildConfig() *Config {
|
|||
|
||||
// Build is the main interface of the package, it gathers the Builder
|
||||
// struct and calls builder.Run() to do all the real build job.
|
||||
func Build(d *daemon.Daemon, buildConfig *Config) error {
|
||||
func Build(ctx context.Context, d *daemon.Daemon, buildConfig *Config) error {
|
||||
var (
|
||||
repoName string
|
||||
tag string
|
||||
|
@ -229,15 +230,15 @@ func Build(d *daemon.Daemon, buildConfig *Config) error {
|
|||
}
|
||||
|
||||
defer func() {
|
||||
builder.Daemon.Graph().Release(builder.id, builder.activeImages...)
|
||||
builder.Daemon.Graph(ctx).Release(builder.id, builder.activeImages...)
|
||||
}()
|
||||
|
||||
id, err := builder.Run(context)
|
||||
id, err := builder.Run(ctx, context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if repoName != "" {
|
||||
return d.Repositories().Tag(repoName, tag, id, true)
|
||||
return d.Repositories(ctx).Tag(repoName, tag, id, true)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -247,7 +248,7 @@ func Build(d *daemon.Daemon, buildConfig *Config) error {
|
|||
//
|
||||
// - call parse.Parse() to get AST root from Dockerfile entries
|
||||
// - do build by calling builder.dispatch() to call all entries' handling routines
|
||||
func BuildFromConfig(d *daemon.Daemon, c *runconfig.Config, changes []string) (*runconfig.Config, error) {
|
||||
func BuildFromConfig(ctx context.Context, d *daemon.Daemon, c *runconfig.Config, changes []string) (*runconfig.Config, error) {
|
||||
ast, err := parser.Parse(bytes.NewBufferString(strings.Join(changes, "\n")))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -269,7 +270,7 @@ func BuildFromConfig(d *daemon.Daemon, c *runconfig.Config, changes []string) (*
|
|||
}
|
||||
|
||||
for i, n := range ast.Children {
|
||||
if err := builder.dispatch(i, n); err != nil {
|
||||
if err := builder.dispatch(ctx, i, n); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@ -289,8 +290,8 @@ type CommitConfig struct {
|
|||
}
|
||||
|
||||
// Commit will create a new image from a container's changes
|
||||
func Commit(name string, d *daemon.Daemon, c *CommitConfig) (string, error) {
|
||||
container, err := d.Get(name)
|
||||
func Commit(ctx context.Context, name string, d *daemon.Daemon, c *CommitConfig) (string, error) {
|
||||
container, err := d.Get(ctx, name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -304,7 +305,7 @@ func Commit(name string, d *daemon.Daemon, c *CommitConfig) (string, error) {
|
|||
c.Config = &runconfig.Config{}
|
||||
}
|
||||
|
||||
newConfig, err := BuildFromConfig(d, c.Config, c.Changes)
|
||||
newConfig, err := BuildFromConfig(ctx, d, c.Config, c.Changes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -322,7 +323,7 @@ func Commit(name string, d *daemon.Daemon, c *CommitConfig) (string, error) {
|
|||
Config: newConfig,
|
||||
}
|
||||
|
||||
img, err := d.Commit(container, commitCfg)
|
||||
img, err := d.Commit(ctx, container, commitCfg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/chrootarchive"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
|
@ -20,8 +21,8 @@ var ErrExtractPointNotDirectory = errors.New("extraction point is not a director
|
|||
|
||||
// ContainerCopy performs a deprecated operation of archiving the resource at
|
||||
// the specified path in the conatiner identified by the given name.
|
||||
func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, error) {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerCopy(ctx context.Context, name string, res string) (io.ReadCloser, error) {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -30,30 +31,30 @@ func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, err
|
|||
res = res[1:]
|
||||
}
|
||||
|
||||
return container.copy(res)
|
||||
return container.copy(ctx, res)
|
||||
}
|
||||
|
||||
// ContainerStatPath stats the filesystem resource at the specified path in the
|
||||
// container identified by the given name.
|
||||
func (daemon *Daemon) ContainerStatPath(name string, path string) (stat *types.ContainerPathStat, err error) {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerStatPath(ctx context.Context, name string, path string) (stat *types.ContainerPathStat, err error) {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return container.StatPath(path)
|
||||
return container.StatPath(ctx, path)
|
||||
}
|
||||
|
||||
// ContainerArchivePath creates an archive of the filesystem resource at the
|
||||
// specified path in the container identified by the given name. Returns a
|
||||
// tar archive of the resource and whether it was a directory or a single file.
|
||||
func (daemon *Daemon) ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error) {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerArchivePath(ctx context.Context, name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error) {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return container.ArchivePath(path)
|
||||
return container.ArchivePath(ctx, path)
|
||||
}
|
||||
|
||||
// ContainerExtractToDir extracts the given archive to the specified location
|
||||
|
@ -62,13 +63,13 @@ func (daemon *Daemon) ContainerArchivePath(name string, path string) (content io
|
|||
// be ErrExtractPointNotDirectory. If noOverwriteDirNonDir is true then it will
|
||||
// be an error if unpacking the given content would cause an existing directory
|
||||
// to be replaced with a non-directory and vice versa.
|
||||
func (daemon *Daemon) ContainerExtractToDir(name, path string, noOverwriteDirNonDir bool, content io.Reader) error {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerExtractToDir(ctx context.Context, name, path string, noOverwriteDirNonDir bool, content io.Reader) error {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return container.ExtractToDir(path, noOverwriteDirNonDir, content)
|
||||
return container.ExtractToDir(ctx, path, noOverwriteDirNonDir, content)
|
||||
}
|
||||
|
||||
// resolvePath resolves the given path in the container to a resource on the
|
||||
|
@ -133,14 +134,14 @@ func (container *Container) statPath(resolvedPath, absPath string) (stat *types.
|
|||
|
||||
// StatPath stats the filesystem resource at the specified path in this
|
||||
// container. Returns stat info about the resource.
|
||||
func (container *Container) StatPath(path string) (stat *types.ContainerPathStat, err error) {
|
||||
func (container *Container) StatPath(ctx context.Context, path string) (stat *types.ContainerPathStat, err error) {
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
|
||||
if err = container.Mount(); err != nil {
|
||||
if err = container.Mount(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer container.Unmount()
|
||||
defer container.Unmount(ctx)
|
||||
|
||||
err = container.mountVolumes()
|
||||
defer container.unmountVolumes(true)
|
||||
|
@ -159,7 +160,7 @@ func (container *Container) StatPath(path string) (stat *types.ContainerPathStat
|
|||
// ArchivePath creates an archive of the filesystem resource at the specified
|
||||
// path in this container. Returns a tar archive of the resource and stat info
|
||||
// about the resource.
|
||||
func (container *Container) ArchivePath(path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error) {
|
||||
func (container *Container) ArchivePath(ctx context.Context, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error) {
|
||||
container.Lock()
|
||||
|
||||
defer func() {
|
||||
|
@ -171,7 +172,7 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta
|
|||
}
|
||||
}()
|
||||
|
||||
if err = container.Mount(); err != nil {
|
||||
if err = container.Mount(ctx); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
|
@ -180,7 +181,7 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta
|
|||
// unmount any volumes
|
||||
container.unmountVolumes(true)
|
||||
// unmount the container's rootfs
|
||||
container.Unmount()
|
||||
container.Unmount(ctx)
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -214,12 +215,12 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta
|
|||
content = ioutils.NewReadCloserWrapper(data, func() error {
|
||||
err := data.Close()
|
||||
container.unmountVolumes(true)
|
||||
container.Unmount()
|
||||
container.Unmount(ctx)
|
||||
container.Unlock()
|
||||
return err
|
||||
})
|
||||
|
||||
container.logEvent("archive-path")
|
||||
container.logEvent(ctx, "archive-path")
|
||||
|
||||
return content, stat, nil
|
||||
}
|
||||
|
@ -230,14 +231,14 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta
|
|||
// noOverwriteDirNonDir is true then it will be an error if unpacking the
|
||||
// given content would cause an existing directory to be replaced with a non-
|
||||
// directory and vice versa.
|
||||
func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool, content io.Reader) (err error) {
|
||||
func (container *Container) ExtractToDir(ctx context.Context, path string, noOverwriteDirNonDir bool, content io.Reader) (err error) {
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
|
||||
if err = container.Mount(); err != nil {
|
||||
if err = container.Mount(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
defer container.Unmount()
|
||||
defer container.Unmount(ctx)
|
||||
|
||||
err = container.mountVolumes()
|
||||
defer container.unmountVolumes(true)
|
||||
|
@ -318,7 +319,7 @@ func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool,
|
|||
return err
|
||||
}
|
||||
|
||||
container.logEvent("extract-to-dir")
|
||||
container.logEvent(ctx, "extract-to-dir")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package daemon
|
|||
import (
|
||||
"io"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
)
|
||||
|
||||
|
@ -15,8 +16,8 @@ type ContainerAttachWithLogsConfig struct {
|
|||
}
|
||||
|
||||
// ContainerAttachWithLogs attaches to logs according to the config passed in. See ContainerAttachWithLogsConfig.
|
||||
func (daemon *Daemon) ContainerAttachWithLogs(prefixOrName string, c *ContainerAttachWithLogsConfig) error {
|
||||
container, err := daemon.Get(prefixOrName)
|
||||
func (daemon *Daemon) ContainerAttachWithLogs(ctx context.Context, prefixOrName string, c *ContainerAttachWithLogsConfig) error {
|
||||
container, err := daemon.Get(ctx, prefixOrName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -43,7 +44,7 @@ func (daemon *Daemon) ContainerAttachWithLogs(prefixOrName string, c *ContainerA
|
|||
stderr = errStream
|
||||
}
|
||||
|
||||
return container.attachWithLogs(stdin, stdout, stderr, c.Logs, c.Stream)
|
||||
return container.attachWithLogs(ctx, stdin, stdout, stderr, c.Logs, c.Stream)
|
||||
}
|
||||
|
||||
// ContainerWsAttachWithLogsConfig attach with websockets, since all
|
||||
|
@ -55,10 +56,10 @@ type ContainerWsAttachWithLogsConfig struct {
|
|||
}
|
||||
|
||||
// ContainerWsAttachWithLogs websocket connection
|
||||
func (daemon *Daemon) ContainerWsAttachWithLogs(prefixOrName string, c *ContainerWsAttachWithLogsConfig) error {
|
||||
container, err := daemon.Get(prefixOrName)
|
||||
func (daemon *Daemon) ContainerWsAttachWithLogs(ctx context.Context, prefixOrName string, c *ContainerWsAttachWithLogsConfig) error {
|
||||
container, err := daemon.Get(ctx, prefixOrName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return container.attachWithLogs(c.InStream, c.OutStream, c.ErrStream, c.Logs, c.Stream)
|
||||
return container.attachWithLogs(ctx, c.InStream, c.OutStream, c.ErrStream, c.Logs, c.Stream)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package daemon
|
||||
|
||||
import "github.com/docker/docker/pkg/archive"
|
||||
import (
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
)
|
||||
|
||||
// ContainerChanges returns a list of container fs changes
|
||||
func (daemon *Daemon) ContainerChanges(name string) ([]archive.Change, error) {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerChanges(ctx context.Context, name string) ([]archive.Change, error) {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/runconfig"
|
||||
)
|
||||
|
@ -18,10 +19,10 @@ type ContainerCommitConfig struct {
|
|||
|
||||
// Commit creates a new filesystem image from the current state of a container.
|
||||
// The image can optionally be tagged into a repository.
|
||||
func (daemon *Daemon) Commit(container *Container, c *ContainerCommitConfig) (*image.Image, error) {
|
||||
func (daemon *Daemon) Commit(ctx context.Context, container *Container, c *ContainerCommitConfig) (*image.Image, error) {
|
||||
if c.Pause && !container.isPaused() {
|
||||
container.pause()
|
||||
defer container.unpause()
|
||||
container.pause(ctx)
|
||||
defer container.unpause(ctx)
|
||||
}
|
||||
|
||||
rwTar, err := container.exportContainerRw()
|
||||
|
@ -46,6 +47,6 @@ func (daemon *Daemon) Commit(container *Container, c *ContainerCommitConfig) (*i
|
|||
return img, err
|
||||
}
|
||||
}
|
||||
container.logEvent("commit")
|
||||
container.logEvent(ctx, "commit")
|
||||
return img, nil
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/opencontainers/runc/libcontainer/label"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/daemon/logger"
|
||||
"github.com/docker/docker/daemon/logger/jsonfilelog"
|
||||
|
@ -170,9 +171,10 @@ func (container *Container) writeHostConfig() error {
|
|||
return ioutil.WriteFile(pth, data, 0666)
|
||||
}
|
||||
|
||||
func (container *Container) logEvent(action string) {
|
||||
func (container *Container) logEvent(ctx context.Context, action string) {
|
||||
d := container.daemon
|
||||
d.EventsService.Log(
|
||||
ctx,
|
||||
action,
|
||||
container.ID,
|
||||
container.Config.Image,
|
||||
|
@ -238,7 +240,7 @@ func (container *Container) exportContainerRw() (archive.Archive, error) {
|
|||
// container needs, such as storage and networking, as well as links
|
||||
// between containers. The container is left waiting for a signal to
|
||||
// begin running.
|
||||
func (container *Container) Start() (err error) {
|
||||
func (container *Container) Start(ctx context.Context) (err error) {
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
|
||||
|
@ -260,12 +262,12 @@ func (container *Container) Start() (err error) {
|
|||
container.ExitCode = 128
|
||||
}
|
||||
container.toDisk()
|
||||
container.cleanup()
|
||||
container.logEvent("die")
|
||||
container.cleanup(ctx)
|
||||
container.logEvent(ctx, "die")
|
||||
}
|
||||
}()
|
||||
|
||||
if err := container.Mount(); err != nil {
|
||||
if err := container.Mount(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -273,10 +275,10 @@ func (container *Container) Start() (err error) {
|
|||
// backwards API compatibility.
|
||||
container.hostConfig = runconfig.SetDefaultNetModeIfBlank(container.hostConfig)
|
||||
|
||||
if err := container.initializeNetworking(); err != nil {
|
||||
if err := container.initializeNetworking(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
linkedEnv, err := container.setupLinkedContainers()
|
||||
linkedEnv, err := container.setupLinkedContainers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -284,7 +286,7 @@ func (container *Container) Start() (err error) {
|
|||
return err
|
||||
}
|
||||
env := container.createDaemonEnvironment(linkedEnv)
|
||||
if err := populateCommand(container, env); err != nil {
|
||||
if err := populateCommand(ctx, container, env); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -301,7 +303,7 @@ func (container *Container) Start() (err error) {
|
|||
mounts = append(mounts, container.ipcMounts()...)
|
||||
|
||||
container.command.Mounts = mounts
|
||||
return container.waitForStart()
|
||||
return container.waitForStart(ctx)
|
||||
}
|
||||
|
||||
// streamConfig.StdinPipe returns a WriteCloser which can be used to feed data
|
||||
|
@ -334,14 +336,14 @@ func (container *Container) isNetworkAllocated() bool {
|
|||
|
||||
// cleanup releases any network resources allocated to the container along with any rules
|
||||
// around how containers are linked together. It also unmounts the container's root filesystem.
|
||||
func (container *Container) cleanup() {
|
||||
func (container *Container) cleanup(ctx context.Context) {
|
||||
container.releaseNetwork()
|
||||
|
||||
if err := container.unmountIpcMounts(); err != nil {
|
||||
logrus.Errorf("%s: Failed to umount ipc filesystems: %v", container.ID, err)
|
||||
}
|
||||
|
||||
if err := container.Unmount(); err != nil {
|
||||
if err := container.Unmount(ctx); err != nil {
|
||||
logrus.Errorf("%s: Failed to umount filesystem: %v", container.ID, err)
|
||||
}
|
||||
|
||||
|
@ -357,7 +359,7 @@ func (container *Container) cleanup() {
|
|||
// to send the signal. An error is returned if the container is paused
|
||||
// or not running, or if there is a problem returned from the
|
||||
// underlying kill command.
|
||||
func (container *Container) killSig(sig int) error {
|
||||
func (container *Container) killSig(ctx context.Context, sig int) error {
|
||||
logrus.Debugf("Sending %d to %s", sig, container.ID)
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
|
@ -385,13 +387,13 @@ func (container *Container) killSig(sig int) error {
|
|||
if err := container.daemon.kill(container, sig); err != nil {
|
||||
return err
|
||||
}
|
||||
container.logEvent("kill")
|
||||
container.logEvent(ctx, "kill")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wrapper aroung killSig() suppressing "no such process" error.
|
||||
func (container *Container) killPossiblyDeadProcess(sig int) error {
|
||||
err := container.killSig(sig)
|
||||
func (container *Container) killPossiblyDeadProcess(ctx context.Context, sig int) error {
|
||||
err := container.killSig(ctx, sig)
|
||||
if err == syscall.ESRCH {
|
||||
logrus.Debugf("Cannot kill process (pid=%d) with signal %d: no such process.", container.getPID(), sig)
|
||||
return nil
|
||||
|
@ -399,7 +401,7 @@ func (container *Container) killPossiblyDeadProcess(sig int) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (container *Container) pause() error {
|
||||
func (container *Container) pause(ctx context.Context) error {
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
|
||||
|
@ -417,11 +419,11 @@ func (container *Container) pause() error {
|
|||
return err
|
||||
}
|
||||
container.Paused = true
|
||||
container.logEvent("pause")
|
||||
container.logEvent(ctx, "pause")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) unpause() error {
|
||||
func (container *Container) unpause(ctx context.Context) error {
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
|
||||
|
@ -439,18 +441,18 @@ func (container *Container) unpause() error {
|
|||
return err
|
||||
}
|
||||
container.Paused = false
|
||||
container.logEvent("unpause")
|
||||
container.logEvent(ctx, "unpause")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Kill forcefully terminates a container.
|
||||
func (container *Container) Kill() error {
|
||||
func (container *Container) Kill(ctx context.Context) error {
|
||||
if !container.IsRunning() {
|
||||
return derr.ErrorCodeNotRunning.WithArgs(container.ID)
|
||||
}
|
||||
|
||||
// 1. Send SIGKILL
|
||||
if err := container.killPossiblyDeadProcess(int(syscall.SIGKILL)); err != nil {
|
||||
if err := container.killPossiblyDeadProcess(ctx, int(syscall.SIGKILL)); err != nil {
|
||||
// While normally we might "return err" here we're not going to
|
||||
// because if we can't stop the container by this point then
|
||||
// its probably because its already stopped. Meaning, between
|
||||
|
@ -484,15 +486,15 @@ func (container *Container) Kill() error {
|
|||
// process to exit. If a negative duration is given, Stop will wait
|
||||
// for the initial signal forever. If the container is not running Stop returns
|
||||
// immediately.
|
||||
func (container *Container) Stop(seconds int) error {
|
||||
func (container *Container) Stop(ctx context.Context, seconds int) error {
|
||||
if !container.IsRunning() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 1. Send a SIGTERM
|
||||
if err := container.killPossiblyDeadProcess(container.stopSignal()); err != nil {
|
||||
if err := container.killPossiblyDeadProcess(ctx, container.stopSignal()); err != nil {
|
||||
logrus.Infof("Failed to send SIGTERM to the process, force killing")
|
||||
if err := container.killPossiblyDeadProcess(9); err != nil {
|
||||
if err := container.killPossiblyDeadProcess(ctx, 9); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -501,13 +503,13 @@ func (container *Container) Stop(seconds int) error {
|
|||
if _, err := container.WaitStop(time.Duration(seconds) * time.Second); err != nil {
|
||||
logrus.Infof("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds)
|
||||
// 3. If it doesn't, then send SIGKILL
|
||||
if err := container.Kill(); err != nil {
|
||||
if err := container.Kill(ctx); err != nil {
|
||||
container.WaitStop(-1 * time.Second)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
container.logEvent("stop")
|
||||
container.logEvent(ctx, "stop")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -515,61 +517,61 @@ func (container *Container) Stop(seconds int) error {
|
|||
// container. When stopping, wait for the given duration in seconds to
|
||||
// gracefully stop, before forcefully terminating the container. If
|
||||
// given a negative duration, wait forever for a graceful stop.
|
||||
func (container *Container) Restart(seconds int) error {
|
||||
func (container *Container) Restart(ctx context.Context, seconds int) error {
|
||||
// Avoid unnecessarily unmounting and then directly mounting
|
||||
// the container when the container stops and then starts
|
||||
// again
|
||||
if err := container.Mount(); err == nil {
|
||||
defer container.Unmount()
|
||||
if err := container.Mount(ctx); err == nil {
|
||||
defer container.Unmount(ctx)
|
||||
}
|
||||
|
||||
if err := container.Stop(seconds); err != nil {
|
||||
if err := container.Stop(ctx, seconds); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := container.Start(); err != nil {
|
||||
if err := container.Start(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
container.logEvent("restart")
|
||||
container.logEvent(ctx, "restart")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Resize changes the TTY of the process running inside the container
|
||||
// to the given height and width. The container must be running.
|
||||
func (container *Container) Resize(h, w int) error {
|
||||
func (container *Container) Resize(ctx context.Context, h, w int) error {
|
||||
if !container.IsRunning() {
|
||||
return derr.ErrorCodeNotRunning.WithArgs(container.ID)
|
||||
}
|
||||
if err := container.command.ProcessConfig.Terminal.Resize(h, w); err != nil {
|
||||
return err
|
||||
}
|
||||
container.logEvent("resize")
|
||||
container.logEvent(ctx, "resize")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) export() (archive.Archive, error) {
|
||||
if err := container.Mount(); err != nil {
|
||||
func (container *Container) export(ctx context.Context) (archive.Archive, error) {
|
||||
if err := container.Mount(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
archive, err := archive.Tar(container.basefs, archive.Uncompressed)
|
||||
if err != nil {
|
||||
container.Unmount()
|
||||
container.Unmount(ctx)
|
||||
return nil, err
|
||||
}
|
||||
arch := ioutils.NewReadCloserWrapper(archive, func() error {
|
||||
err := archive.Close()
|
||||
container.Unmount()
|
||||
container.Unmount(ctx)
|
||||
return err
|
||||
})
|
||||
container.logEvent("export")
|
||||
container.logEvent(ctx, "export")
|
||||
return arch, err
|
||||
}
|
||||
|
||||
// Mount sets container.basefs
|
||||
func (container *Container) Mount() error {
|
||||
return container.daemon.Mount(container)
|
||||
func (container *Container) Mount(ctx context.Context) error {
|
||||
return container.daemon.Mount(ctx, container)
|
||||
}
|
||||
|
||||
func (container *Container) changes() ([]archive.Change, error) {
|
||||
|
@ -578,7 +580,7 @@ func (container *Container) changes() ([]archive.Change, error) {
|
|||
return container.daemon.changes(container)
|
||||
}
|
||||
|
||||
func (container *Container) getImage() (*image.Image, error) {
|
||||
func (container *Container) getImage(ctx context.Context) (*image.Image, error) {
|
||||
if container.daemon == nil {
|
||||
return nil, derr.ErrorCodeImageUnregContainer
|
||||
}
|
||||
|
@ -587,7 +589,7 @@ func (container *Container) getImage() (*image.Image, error) {
|
|||
|
||||
// Unmount asks the daemon to release the layered filesystems that are
|
||||
// mounted by the container.
|
||||
func (container *Container) Unmount() error {
|
||||
func (container *Container) Unmount(ctx context.Context) error {
|
||||
return container.daemon.unmount(container)
|
||||
}
|
||||
|
||||
|
@ -612,7 +614,7 @@ func validateID(id string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) copy(resource string) (rc io.ReadCloser, err error) {
|
||||
func (container *Container) copy(ctx context.Context, resource string) (rc io.ReadCloser, err error) {
|
||||
container.Lock()
|
||||
|
||||
defer func() {
|
||||
|
@ -624,7 +626,7 @@ func (container *Container) copy(resource string) (rc io.ReadCloser, err error)
|
|||
}
|
||||
}()
|
||||
|
||||
if err := container.Mount(); err != nil {
|
||||
if err := container.Mount(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -633,7 +635,7 @@ func (container *Container) copy(resource string) (rc io.ReadCloser, err error)
|
|||
// unmount any volumes
|
||||
container.unmountVolumes(true)
|
||||
// unmount the container's rootfs
|
||||
container.Unmount()
|
||||
container.Unmount(ctx)
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -669,11 +671,11 @@ func (container *Container) copy(resource string) (rc io.ReadCloser, err error)
|
|||
reader := ioutils.NewReadCloserWrapper(archive, func() error {
|
||||
err := archive.Close()
|
||||
container.unmountVolumes(true)
|
||||
container.Unmount()
|
||||
container.Unmount(ctx)
|
||||
container.Unlock()
|
||||
return err
|
||||
})
|
||||
container.logEvent("copy")
|
||||
container.logEvent(ctx, "copy")
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
|
@ -752,14 +754,14 @@ func (container *Container) startLogging() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) waitForStart() error {
|
||||
func (container *Container) waitForStart(ctx context.Context) error {
|
||||
container.monitor = newContainerMonitor(container, container.hostConfig.RestartPolicy)
|
||||
|
||||
// block until we either receive an error from the initial start of the container's
|
||||
// process or until the process is running in the container
|
||||
select {
|
||||
case <-container.monitor.startSignal:
|
||||
case err := <-promise.Go(container.monitor.Start):
|
||||
case err := <-promise.Go(func() error { return container.monitor.Start(ctx) }):
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -790,11 +792,11 @@ func (container *Container) getExecIDs() []string {
|
|||
return container.execCommands.List()
|
||||
}
|
||||
|
||||
func (container *Container) exec(ExecConfig *ExecConfig) error {
|
||||
func (container *Container) exec(ctx context.Context, ExecConfig *ExecConfig) error {
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
|
||||
callback := func(processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error {
|
||||
callback := func(ctx context.Context, processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error {
|
||||
if processConfig.Tty {
|
||||
// The callback is called after the process Start()
|
||||
// so we are in the parent process. In TTY mode, stdin/out/err is the PtySlave
|
||||
|
@ -809,7 +811,7 @@ func (container *Container) exec(ExecConfig *ExecConfig) error {
|
|||
|
||||
// We use a callback here instead of a goroutine and an chan for
|
||||
// synchronization purposes
|
||||
cErr := promise.Go(func() error { return container.monitorExec(ExecConfig, callback) })
|
||||
cErr := promise.Go(func() error { return container.monitorExec(ctx, ExecConfig, callback) })
|
||||
|
||||
// Exec should not return until the process is actually running
|
||||
select {
|
||||
|
@ -821,13 +823,13 @@ func (container *Container) exec(ExecConfig *ExecConfig) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) monitorExec(ExecConfig *ExecConfig, callback execdriver.DriverCallback) error {
|
||||
func (container *Container) monitorExec(ctx context.Context, ExecConfig *ExecConfig, callback execdriver.DriverCallback) error {
|
||||
var (
|
||||
err error
|
||||
exitCode int
|
||||
)
|
||||
pipes := execdriver.NewPipes(ExecConfig.streamConfig.stdin, ExecConfig.streamConfig.stdout, ExecConfig.streamConfig.stderr, ExecConfig.OpenStdin)
|
||||
exitCode, err = container.daemon.Exec(container, ExecConfig, pipes, callback)
|
||||
exitCode, err = container.daemon.Exec(ctx, container, ExecConfig, pipes, callback)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error running command in existing container %s: %s", container.ID, err)
|
||||
}
|
||||
|
@ -860,7 +862,7 @@ func (container *Container) Attach(stdin io.ReadCloser, stdout io.Writer, stderr
|
|||
return attach(&container.streamConfig, container.Config.OpenStdin, container.Config.StdinOnce, container.Config.Tty, stdin, stdout, stderr)
|
||||
}
|
||||
|
||||
func (container *Container) attachWithLogs(stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool) error {
|
||||
func (container *Container) attachWithLogs(ctx context.Context, stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool) error {
|
||||
if logs {
|
||||
logDriver, err := container.getLogger()
|
||||
if err != nil {
|
||||
|
@ -892,7 +894,7 @@ func (container *Container) attachWithLogs(stdin io.ReadCloser, stdout, stderr i
|
|||
}
|
||||
}
|
||||
|
||||
container.logEvent("attach")
|
||||
container.logEvent(ctx, "attach")
|
||||
|
||||
//stream
|
||||
if stream {
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/daemon/links"
|
||||
"github.com/docker/docker/daemon/network"
|
||||
|
@ -77,12 +78,12 @@ func killProcessDirectly(container *Container) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) setupLinkedContainers() ([]string, error) {
|
||||
func (container *Container) setupLinkedContainers(ctx context.Context) ([]string, error) {
|
||||
var (
|
||||
env []string
|
||||
daemon = container.daemon
|
||||
)
|
||||
children, err := daemon.children(container.Name)
|
||||
children, err := daemon.children(ctx, container.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -175,7 +176,7 @@ func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs.
|
|||
return devs, derr.ErrorCodeDeviceInfo.WithArgs(deviceMapping.PathOnHost, err)
|
||||
}
|
||||
|
||||
func populateCommand(c *Container, env []string) error {
|
||||
func populateCommand(ctx context.Context, c *Container, env []string) error {
|
||||
var en *execdriver.Network
|
||||
if !c.Config.NetworkDisabled {
|
||||
en = &execdriver.Network{}
|
||||
|
@ -185,7 +186,7 @@ func populateCommand(c *Container, env []string) error {
|
|||
|
||||
parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2)
|
||||
if parts[0] == "container" {
|
||||
nc, err := c.getNetworkedContainer()
|
||||
nc, err := c.getNetworkedContainer(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -206,7 +207,7 @@ func populateCommand(c *Container, env []string) error {
|
|||
}
|
||||
|
||||
if c.hostConfig.IpcMode.IsContainer() {
|
||||
ic, err := c.getIpcContainer()
|
||||
ic, err := c.getIpcContainer(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -348,18 +349,18 @@ func mergeDevices(defaultDevices, userDevices []*configs.Device) []*configs.Devi
|
|||
}
|
||||
|
||||
// GetSize returns the real size & virtual size of the container.
|
||||
func (container *Container) getSize() (int64, int64) {
|
||||
func (container *Container) getSize(ctx context.Context) (int64, int64) {
|
||||
var (
|
||||
sizeRw, sizeRootfs int64
|
||||
err error
|
||||
driver = container.daemon.driver
|
||||
)
|
||||
|
||||
if err := container.Mount(); err != nil {
|
||||
if err := container.Mount(ctx); err != nil {
|
||||
logrus.Errorf("Failed to compute size of container rootfs %s: %s", container.ID, err)
|
||||
return sizeRw, sizeRootfs
|
||||
}
|
||||
defer container.Unmount()
|
||||
defer container.Unmount(ctx)
|
||||
|
||||
initID := fmt.Sprintf("%s-init", container.ID)
|
||||
sizeRw, err = driver.DiffSize(container.ID, initID)
|
||||
|
@ -411,7 +412,7 @@ func (container *Container) buildHostnameFile() error {
|
|||
return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
|
||||
}
|
||||
|
||||
func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, error) {
|
||||
func (container *Container) buildSandboxOptions(ctx context.Context) ([]libnetwork.SandboxOption, error) {
|
||||
var (
|
||||
sboxOptions []libnetwork.SandboxOption
|
||||
err error
|
||||
|
@ -488,7 +489,7 @@ func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, e
|
|||
|
||||
var childEndpoints, parentEndpoints []string
|
||||
|
||||
children, err := container.daemon.children(container.Name)
|
||||
children, err := container.daemon.children(ctx, container.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -519,7 +520,7 @@ func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, e
|
|||
continue
|
||||
}
|
||||
|
||||
c, err := container.daemon.Get(ref.ParentID)
|
||||
c, err := container.daemon.Get(ctx, ref.ParentID)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
|
@ -678,7 +679,7 @@ func (container *Container) updateSandboxNetworkSettings(sb libnetwork.Sandbox)
|
|||
|
||||
// UpdateNetwork is used to update the container's network (e.g. when linked containers
|
||||
// get removed/unlinked).
|
||||
func (container *Container) updateNetwork() error {
|
||||
func (container *Container) updateNetwork(ctx context.Context) error {
|
||||
ctrl := container.daemon.netController
|
||||
sid := container.NetworkSettings.SandboxID
|
||||
|
||||
|
@ -687,7 +688,7 @@ func (container *Container) updateNetwork() error {
|
|||
return derr.ErrorCodeNoSandbox.WithArgs(sid, err)
|
||||
}
|
||||
|
||||
options, err := container.buildSandboxOptions()
|
||||
options, err := container.buildSandboxOptions(ctx)
|
||||
if err != nil {
|
||||
return derr.ErrorCodeNetworkUpdate.WithArgs(err)
|
||||
}
|
||||
|
@ -811,7 +812,7 @@ func createNetwork(controller libnetwork.NetworkController, dnet string, driver
|
|||
return controller.NewNetwork(driver, dnet, createOptions...)
|
||||
}
|
||||
|
||||
func (container *Container) secondaryNetworkRequired(primaryNetworkType string) bool {
|
||||
func (container *Container) secondaryNetworkRequired(ctx context.Context, primaryNetworkType string) bool {
|
||||
switch primaryNetworkType {
|
||||
case "bridge", "none", "host", "container":
|
||||
return false
|
||||
|
@ -830,7 +831,7 @@ func (container *Container) secondaryNetworkRequired(primaryNetworkType string)
|
|||
return false
|
||||
}
|
||||
|
||||
func (container *Container) allocateNetwork() error {
|
||||
func (container *Container) allocateNetwork(ctx context.Context) error {
|
||||
mode := container.hostConfig.NetworkMode
|
||||
controller := container.daemon.netController
|
||||
if container.Config.NetworkDisabled || mode.IsContainer() {
|
||||
|
@ -864,21 +865,21 @@ func (container *Container) allocateNetwork() error {
|
|||
service = strings.Replace(service, "/", "", -1)
|
||||
}
|
||||
|
||||
if container.secondaryNetworkRequired(networkDriver) {
|
||||
if container.secondaryNetworkRequired(ctx, networkDriver) {
|
||||
// Configure Bridge as secondary network for port binding purposes
|
||||
if err := container.configureNetwork("bridge", service, "bridge", false); err != nil {
|
||||
if err := container.configureNetwork(ctx, "bridge", service, "bridge", false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := container.configureNetwork(networkName, service, networkDriver, mode.IsDefault()); err != nil {
|
||||
if err := container.configureNetwork(ctx, networkName, service, networkDriver, mode.IsDefault()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return container.writeHostConfig()
|
||||
}
|
||||
|
||||
func (container *Container) configureNetwork(networkName, service, networkDriver string, canCreateNetwork bool) error {
|
||||
func (container *Container) configureNetwork(ctx context.Context, networkName, service, networkDriver string, canCreateNetwork bool) error {
|
||||
controller := container.daemon.netController
|
||||
|
||||
n, err := controller.NetworkByName(networkName)
|
||||
|
@ -922,7 +923,7 @@ func (container *Container) configureNetwork(networkName, service, networkDriver
|
|||
return false
|
||||
})
|
||||
if sb == nil {
|
||||
options, err := container.buildSandboxOptions()
|
||||
options, err := container.buildSandboxOptions(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -945,12 +946,12 @@ func (container *Container) configureNetwork(networkName, service, networkDriver
|
|||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) initializeNetworking() error {
|
||||
func (container *Container) initializeNetworking(ctx context.Context) error {
|
||||
var err error
|
||||
|
||||
if container.hostConfig.NetworkMode.IsContainer() {
|
||||
// we need to get the hosts files from the container to join
|
||||
nc, err := container.getNetworkedContainer()
|
||||
nc, err := container.getNetworkedContainer(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -976,7 +977,7 @@ func (container *Container) initializeNetworking() error {
|
|||
|
||||
}
|
||||
|
||||
if err := container.allocateNetwork(); err != nil {
|
||||
if err := container.allocateNetwork(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -997,9 +998,9 @@ func (container *Container) setNetworkNamespaceKey(pid int) error {
|
|||
return sandbox.SetKey(path)
|
||||
}
|
||||
|
||||
func (container *Container) getIpcContainer() (*Container, error) {
|
||||
func (container *Container) getIpcContainer(ctx context.Context) (*Container, error) {
|
||||
containerID := container.hostConfig.IpcMode.Container()
|
||||
c, err := container.daemon.Get(containerID)
|
||||
c, err := container.daemon.Get(ctx, containerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1035,14 +1036,14 @@ func (container *Container) setupWorkingDirectory() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) getNetworkedContainer() (*Container, error) {
|
||||
func (container *Container) getNetworkedContainer(ctx context.Context) (*Container, error) {
|
||||
parts := strings.SplitN(string(container.hostConfig.NetworkMode), ":", 2)
|
||||
switch parts[0] {
|
||||
case "container":
|
||||
if len(parts) != 2 {
|
||||
return nil, derr.ErrorCodeParseContainer
|
||||
}
|
||||
nc, err := container.daemon.Get(parts[1])
|
||||
nc, err := container.daemon.Get(ctx, parts[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ package daemon
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
derr "github.com/docker/docker/errors"
|
||||
)
|
||||
|
@ -25,7 +26,7 @@ func killProcessDirectly(container *Container) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) setupLinkedContainers() ([]string, error) {
|
||||
func (container *Container) setupLinkedContainers(ctx context.Context) ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
@ -34,7 +35,7 @@ func (container *Container) createDaemonEnvironment(linkedEnv []string) []string
|
|||
return container.Config.Env
|
||||
}
|
||||
|
||||
func (container *Container) initializeNetworking() error {
|
||||
func (container *Container) initializeNetworking(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -42,7 +43,7 @@ func (container *Container) setupWorkingDirectory() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func populateCommand(c *Container, env []string) error {
|
||||
func populateCommand(ctx context.Context, c *Container, env []string) error {
|
||||
en := &execdriver.Network{
|
||||
Interface: nil,
|
||||
}
|
||||
|
@ -135,7 +136,7 @@ func populateCommand(c *Container, env []string) error {
|
|||
}
|
||||
|
||||
// GetSize returns real size & virtual size
|
||||
func (container *Container) getSize() (int64, int64) {
|
||||
func (container *Container) getSize(ctx context.Context) (int64, int64) {
|
||||
// TODO Windows
|
||||
return 0, 0
|
||||
}
|
||||
|
@ -150,7 +151,7 @@ func (container *Container) allocateNetwork() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) updateNetwork() error {
|
||||
func (container *Container) updateNetwork(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/context"
|
||||
derr "github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/graph/tags"
|
||||
"github.com/docker/docker/image"
|
||||
|
@ -15,21 +16,21 @@ import (
|
|||
)
|
||||
|
||||
// ContainerCreate takes configs and creates a container.
|
||||
func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hostConfig *runconfig.HostConfig, adjustCPUShares bool) (*Container, []string, error) {
|
||||
func (daemon *Daemon) ContainerCreate(ctx context.Context, name string, config *runconfig.Config, hostConfig *runconfig.HostConfig, adjustCPUShares bool) (*Container, []string, error) {
|
||||
if config == nil {
|
||||
return nil, nil, derr.ErrorCodeEmptyConfig
|
||||
}
|
||||
|
||||
warnings, err := daemon.verifyContainerSettings(hostConfig, config)
|
||||
warnings, err := daemon.verifyContainerSettings(ctx, hostConfig, config)
|
||||
if err != nil {
|
||||
return nil, warnings, err
|
||||
}
|
||||
|
||||
daemon.adaptContainerSettings(hostConfig, adjustCPUShares)
|
||||
|
||||
container, buildWarnings, err := daemon.Create(config, hostConfig, name)
|
||||
container, buildWarnings, err := daemon.Create(ctx, config, hostConfig, name)
|
||||
if err != nil {
|
||||
if daemon.Graph().IsNotExist(err, config.Image) {
|
||||
if daemon.Graph(ctx).IsNotExist(err, config.Image) {
|
||||
if strings.Contains(config.Image, "@") {
|
||||
return nil, warnings, derr.ErrorCodeNoSuchImageHash.WithArgs(config.Image)
|
||||
}
|
||||
|
@ -48,7 +49,7 @@ func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hos
|
|||
}
|
||||
|
||||
// Create creates a new container from the given configuration with a given name.
|
||||
func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.HostConfig, name string) (retC *Container, retS []string, retErr error) {
|
||||
func (daemon *Daemon) Create(ctx context.Context, config *runconfig.Config, hostConfig *runconfig.HostConfig, name string) (retC *Container, retS []string, retErr error) {
|
||||
var (
|
||||
container *Container
|
||||
warnings []string
|
||||
|
@ -76,29 +77,29 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos
|
|||
hostConfig = &runconfig.HostConfig{}
|
||||
}
|
||||
if hostConfig.SecurityOpt == nil {
|
||||
hostConfig.SecurityOpt, err = daemon.generateSecurityOpt(hostConfig.IpcMode, hostConfig.PidMode)
|
||||
hostConfig.SecurityOpt, err = daemon.generateSecurityOpt(ctx, hostConfig.IpcMode, hostConfig.PidMode)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
if container, err = daemon.newContainer(name, config, imgID); err != nil {
|
||||
if container, err = daemon.newContainer(ctx, name, config, imgID); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
if err := daemon.rm(container, false); err != nil {
|
||||
if err := daemon.rm(ctx, container, false); err != nil {
|
||||
logrus.Errorf("Clean up Error! Cannot destroy container %s: %v", container.ID, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if err := daemon.Register(container); err != nil {
|
||||
if err := daemon.Register(ctx, container); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := daemon.createRootfs(container); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := daemon.setHostConfig(container, hostConfig); err != nil {
|
||||
if err := daemon.setHostConfig(ctx, container, hostConfig); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer func() {
|
||||
|
@ -108,10 +109,10 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos
|
|||
}
|
||||
}
|
||||
}()
|
||||
if err := container.Mount(); err != nil {
|
||||
if err := container.Mount(ctx); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer container.Unmount()
|
||||
defer container.Unmount(ctx)
|
||||
|
||||
if err := createContainerPlatformSpecificSettings(container, config, hostConfig, img); err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -121,16 +122,16 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos
|
|||
logrus.Errorf("Error saving new container to disk: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
container.logEvent("create")
|
||||
container.logEvent(ctx, "create")
|
||||
return container, warnings, nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) generateSecurityOpt(ipcMode runconfig.IpcMode, pidMode runconfig.PidMode) ([]string, error) {
|
||||
func (daemon *Daemon) generateSecurityOpt(ctx context.Context, ipcMode runconfig.IpcMode, pidMode runconfig.PidMode) ([]string, error) {
|
||||
if ipcMode.IsHost() || pidMode.IsHost() {
|
||||
return label.DisableSecOpt(), nil
|
||||
}
|
||||
if ipcContainer := ipcMode.Container(); ipcContainer != "" {
|
||||
c, err := daemon.Get(ipcContainer)
|
||||
c, err := daemon.Get(ctx, ipcContainer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -142,7 +143,7 @@ func (daemon *Daemon) generateSecurityOpt(ipcMode runconfig.IpcMode, pidMode run
|
|||
|
||||
// VolumeCreate creates a volume with the specified name, driver, and opts
|
||||
// This is called directly from the remote API
|
||||
func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]string) (*types.Volume, error) {
|
||||
func (daemon *Daemon) VolumeCreate(ctx context.Context, name, driverName string, opts map[string]string) (*types.Volume, error) {
|
||||
if name == "" {
|
||||
name = stringid.GenerateNonCryptoID()
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/events"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/daemon/execdriver/execdrivers"
|
||||
|
@ -127,14 +128,14 @@ type Daemon struct {
|
|||
// - A partial container ID prefix (e.g. short ID) of any length that is
|
||||
// unique enough to only return a single container object
|
||||
// If none of these searches succeed, an error is returned
|
||||
func (daemon *Daemon) Get(prefixOrName string) (*Container, error) {
|
||||
func (daemon *Daemon) Get(ctx context.Context, prefixOrName string) (*Container, error) {
|
||||
if containerByID := daemon.containers.Get(prefixOrName); containerByID != nil {
|
||||
// prefix is an exact match to a full container ID
|
||||
return containerByID, nil
|
||||
}
|
||||
|
||||
// GetByName will match only an exact name provided; we ignore errors
|
||||
if containerByName, _ := daemon.GetByName(prefixOrName); containerByName != nil {
|
||||
if containerByName, _ := daemon.GetByName(ctx, prefixOrName); containerByName != nil {
|
||||
// prefix is an exact match to a full container Name
|
||||
return containerByName, nil
|
||||
}
|
||||
|
@ -152,8 +153,8 @@ func (daemon *Daemon) Get(prefixOrName string) (*Container, error) {
|
|||
|
||||
// Exists returns a true if a container of the specified ID or name exists,
|
||||
// false otherwise.
|
||||
func (daemon *Daemon) Exists(id string) bool {
|
||||
c, _ := daemon.Get(id)
|
||||
func (daemon *Daemon) Exists(ctx context.Context, id string) bool {
|
||||
c, _ := daemon.Get(ctx, id)
|
||||
return c != nil
|
||||
}
|
||||
|
||||
|
@ -178,8 +179,8 @@ func (daemon *Daemon) load(id string) (*Container, error) {
|
|||
}
|
||||
|
||||
// Register makes a container object usable by the daemon as <container.ID>
|
||||
func (daemon *Daemon) Register(container *Container) error {
|
||||
if container.daemon != nil || daemon.Exists(container.ID) {
|
||||
func (daemon *Daemon) Register(ctx context.Context, container *Container) error {
|
||||
if container.daemon != nil || daemon.Exists(ctx, container.ID) {
|
||||
return fmt.Errorf("Container is already loaded")
|
||||
}
|
||||
if err := validateID(container.ID); err != nil {
|
||||
|
@ -217,10 +218,7 @@ func (daemon *Daemon) Register(container *Container) error {
|
|||
}
|
||||
daemon.execDriver.Terminate(cmd)
|
||||
|
||||
if err := container.unmountIpcMounts(); err != nil {
|
||||
logrus.Errorf("%s: Failed to umount ipc filesystems: %v", container.ID, err)
|
||||
}
|
||||
if err := container.Unmount(); err != nil {
|
||||
if err := container.Unmount(ctx); err != nil {
|
||||
logrus.Debugf("unmount error %s", err)
|
||||
}
|
||||
if err := container.toDiskLocking(); err != nil {
|
||||
|
@ -254,7 +252,7 @@ func (daemon *Daemon) ensureName(container *Container) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) restore() error {
|
||||
func (daemon *Daemon) restore(ctx context.Context) error {
|
||||
type cr struct {
|
||||
container *Container
|
||||
registered bool
|
||||
|
@ -324,7 +322,7 @@ func (daemon *Daemon) restore() error {
|
|||
}
|
||||
}
|
||||
|
||||
if err := daemon.Register(container); err != nil {
|
||||
if err := daemon.Register(ctx, container); err != nil {
|
||||
logrus.Errorf("Failed to register container %s: %s", container.ID, err)
|
||||
// The container register failed should not be started.
|
||||
return
|
||||
|
@ -335,7 +333,7 @@ func (daemon *Daemon) restore() error {
|
|||
if daemon.configStore.AutoRestart && container.shouldRestart() {
|
||||
logrus.Debugf("Starting container %s", container.ID)
|
||||
|
||||
if err := container.Start(); err != nil {
|
||||
if err := container.Start(ctx); err != nil {
|
||||
logrus.Errorf("Failed to start container %s: %s", container.ID, err)
|
||||
}
|
||||
}
|
||||
|
@ -365,7 +363,7 @@ func (daemon *Daemon) mergeAndVerifyConfig(config *runconfig.Config, img *image.
|
|||
return nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) generateIDAndName(name string) (string, string, error) {
|
||||
func (daemon *Daemon) generateIDAndName(ctx context.Context, name string) (string, string, error) {
|
||||
var (
|
||||
err error
|
||||
id = stringid.GenerateNonCryptoID()
|
||||
|
@ -378,14 +376,14 @@ func (daemon *Daemon) generateIDAndName(name string) (string, string, error) {
|
|||
return id, name, nil
|
||||
}
|
||||
|
||||
if name, err = daemon.reserveName(id, name); err != nil {
|
||||
if name, err = daemon.reserveName(ctx, id, name); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return id, name, nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) reserveName(id, name string) (string, error) {
|
||||
func (daemon *Daemon) reserveName(ctx context.Context, id, name string) (string, error) {
|
||||
if !validContainerNamePattern.MatchString(name) {
|
||||
return "", fmt.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars)
|
||||
}
|
||||
|
@ -399,7 +397,7 @@ func (daemon *Daemon) reserveName(id, name string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
conflictingContainer, err := daemon.GetByName(name)
|
||||
conflictingContainer, err := daemon.GetByName(ctx, name)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "Could not find entity") {
|
||||
return "", err
|
||||
|
@ -469,12 +467,12 @@ func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint *stringutils.StrSlic
|
|||
return entrypoint, args
|
||||
}
|
||||
|
||||
func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID string) (*Container, error) {
|
||||
func (daemon *Daemon) newContainer(ctx context.Context, name string, config *runconfig.Config, imgID string) (*Container, error) {
|
||||
var (
|
||||
id string
|
||||
err error
|
||||
)
|
||||
id, name, err = daemon.generateIDAndName(name)
|
||||
id, name, err = daemon.generateIDAndName(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -511,7 +509,7 @@ func GetFullContainerName(name string) (string, error) {
|
|||
}
|
||||
|
||||
// GetByName returns a container given a name.
|
||||
func (daemon *Daemon) GetByName(name string) (*Container, error) {
|
||||
func (daemon *Daemon) GetByName(ctx context.Context, name string) (*Container, error) {
|
||||
fullName, err := GetFullContainerName(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -530,7 +528,7 @@ func (daemon *Daemon) GetByName(name string) (*Container, error) {
|
|||
// children returns all child containers of the container with the
|
||||
// given name. The containers are returned as a map from the container
|
||||
// name to a pointer to Container.
|
||||
func (daemon *Daemon) children(name string) (map[string]*Container, error) {
|
||||
func (daemon *Daemon) children(ctx context.Context, name string) (map[string]*Container, error) {
|
||||
name, err := GetFullContainerName(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -538,7 +536,7 @@ func (daemon *Daemon) children(name string) (map[string]*Container, error) {
|
|||
children := make(map[string]*Container)
|
||||
|
||||
err = daemon.containerGraphDB.Walk(name, func(p string, e *graphdb.Entity) error {
|
||||
c, err := daemon.Get(e.ID())
|
||||
c, err := daemon.Get(ctx, e.ID())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -574,7 +572,7 @@ func (daemon *Daemon) registerLink(parent, child *Container, alias string) error
|
|||
|
||||
// NewDaemon sets up everything for the daemon to be able to service
|
||||
// requests from the webserver.
|
||||
func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemon, err error) {
|
||||
func NewDaemon(ctx context.Context, config *Config, registryService *registry.Service) (daemon *Daemon, err error) {
|
||||
setDefaultMtu(config)
|
||||
|
||||
// Ensure we have compatible configuration options
|
||||
|
@ -642,7 +640,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
|||
// Ensure the graph driver is shutdown at a later point
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if err := d.Shutdown(); err != nil {
|
||||
if err := d.Shutdown(ctx); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
|
@ -776,7 +774,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
|||
|
||||
go d.execCommandGC()
|
||||
|
||||
if err := d.restore(); err != nil {
|
||||
if err := d.restore(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -784,12 +782,12 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
|||
}
|
||||
|
||||
// Shutdown stops the daemon.
|
||||
func (daemon *Daemon) Shutdown() error {
|
||||
func (daemon *Daemon) Shutdown(ctx context.Context) error {
|
||||
daemon.shutdown = true
|
||||
if daemon.containers != nil {
|
||||
group := sync.WaitGroup{}
|
||||
logrus.Debug("starting clean shutdown of all containers...")
|
||||
for _, container := range daemon.List() {
|
||||
for _, container := range daemon.List(ctx) {
|
||||
c := container
|
||||
if c.IsRunning() {
|
||||
logrus.Debugf("stopping %s", c.ID)
|
||||
|
@ -812,7 +810,7 @@ func (daemon *Daemon) Shutdown() error {
|
|||
logrus.Debugf("sending SIGTERM to container %s with error: %v", c.ID, err)
|
||||
return
|
||||
}
|
||||
if err := c.unpause(); err != nil {
|
||||
if err := c.unpause(ctx); err != nil {
|
||||
logrus.Debugf("Failed to unpause container %s with error: %v", c.ID, err)
|
||||
return
|
||||
}
|
||||
|
@ -827,7 +825,7 @@ func (daemon *Daemon) Shutdown() error {
|
|||
}
|
||||
} else {
|
||||
// If container failed to exit in 10 seconds of SIGTERM, then using the force
|
||||
if err := c.Stop(10); err != nil {
|
||||
if err := c.Stop(ctx, 10); err != nil {
|
||||
logrus.Errorf("Stop container %s with error: %v", c.ID, err)
|
||||
}
|
||||
}
|
||||
|
@ -865,7 +863,7 @@ func (daemon *Daemon) Shutdown() error {
|
|||
|
||||
// Mount sets container.basefs
|
||||
// (is it not set coming in? why is it unset?)
|
||||
func (daemon *Daemon) Mount(container *Container) error {
|
||||
func (daemon *Daemon) Mount(ctx context.Context, container *Container) error {
|
||||
dir, err := daemon.driver.Get(container.ID, container.getMountLabel())
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error getting container %s from driver %s: %s", container.ID, daemon.driver, err)
|
||||
|
@ -890,14 +888,14 @@ func (daemon *Daemon) unmount(container *Container) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (execdriver.ExitStatus, error) {
|
||||
func (daemon *Daemon) run(ctx context.Context, c *Container, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (execdriver.ExitStatus, error) {
|
||||
hooks := execdriver.Hooks{
|
||||
Start: startCallback,
|
||||
}
|
||||
hooks.PreStart = append(hooks.PreStart, func(processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error {
|
||||
hooks.PreStart = append(hooks.PreStart, func(ctx context.Context, processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error {
|
||||
return c.setNetworkNamespaceKey(pid)
|
||||
})
|
||||
return daemon.execDriver.Run(c.command, pipes, hooks)
|
||||
return daemon.execDriver.Run(ctx, c.command, pipes, hooks)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) kill(c *Container, sig int) error {
|
||||
|
@ -964,12 +962,12 @@ func (daemon *Daemon) createRootfs(container *Container) error {
|
|||
// which need direct access to daemon.graph.
|
||||
// Once the tests switch to using engine and jobs, this method
|
||||
// can go away.
|
||||
func (daemon *Daemon) Graph() *graph.Graph {
|
||||
func (daemon *Daemon) Graph(ctx context.Context) *graph.Graph {
|
||||
return daemon.graph
|
||||
}
|
||||
|
||||
// Repositories returns all repositories.
|
||||
func (daemon *Daemon) Repositories() *graph.TagStore {
|
||||
func (daemon *Daemon) Repositories(ctx context.Context) *graph.TagStore {
|
||||
return daemon.repositories
|
||||
}
|
||||
|
||||
|
@ -983,13 +981,13 @@ func (daemon *Daemon) systemInitPath() string {
|
|||
|
||||
// GraphDriver returns the currently used driver for processing
|
||||
// container layers.
|
||||
func (daemon *Daemon) GraphDriver() graphdriver.Driver {
|
||||
func (daemon *Daemon) GraphDriver(ctx context.Context) graphdriver.Driver {
|
||||
return daemon.driver
|
||||
}
|
||||
|
||||
// ExecutionDriver returns the currently used driver for creating and
|
||||
// starting execs in a container.
|
||||
func (daemon *Daemon) ExecutionDriver() execdriver.Driver {
|
||||
func (daemon *Daemon) ExecutionDriver(ctx context.Context) execdriver.Driver {
|
||||
return daemon.execDriver
|
||||
}
|
||||
|
||||
|
@ -1001,9 +999,9 @@ func (daemon *Daemon) containerGraph() *graphdb.Database {
|
|||
// of the image with imgID, that had the same config when it was
|
||||
// created. nil is returned if a child cannot be found. An error is
|
||||
// returned if the parent image cannot be found.
|
||||
func (daemon *Daemon) ImageGetCached(imgID string, config *runconfig.Config) (*image.Image, error) {
|
||||
func (daemon *Daemon) ImageGetCached(ctx context.Context, imgID string, config *runconfig.Config) (*image.Image, error) {
|
||||
// Retrieve all images
|
||||
images := daemon.Graph().Map()
|
||||
images := daemon.Graph(ctx).Map()
|
||||
|
||||
// Store the tree in a map of map (map[parentId][childId])
|
||||
imageMap := make(map[string]map[string]struct{})
|
||||
|
@ -1039,7 +1037,7 @@ func tempDir(rootDir string) (string, error) {
|
|||
return tmpDir, system.MkdirAll(tmpDir, 0700)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig.HostConfig) error {
|
||||
func (daemon *Daemon) setHostConfig(ctx context.Context, container *Container, hostConfig *runconfig.HostConfig) error {
|
||||
container.Lock()
|
||||
if err := parseSecurityOpt(container, hostConfig); err != nil {
|
||||
container.Unlock()
|
||||
|
@ -1049,14 +1047,14 @@ func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig.
|
|||
|
||||
// Do not lock while creating volumes since this could be calling out to external plugins
|
||||
// Don't want to block other actions, like `docker ps` because we're waiting on an external plugin
|
||||
if err := daemon.registerMountPoints(container, hostConfig); err != nil {
|
||||
if err := daemon.registerMountPoints(ctx, container, hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
// Register any links from the host config before starting the container
|
||||
if err := daemon.registerLinks(container, hostConfig); err != nil {
|
||||
if err := daemon.registerLinks(ctx, container, hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -1094,7 +1092,7 @@ func getDefaultRouteMtu() (int, error) {
|
|||
|
||||
// verifyContainerSettings performs validation of the hostconfig and config
|
||||
// structures.
|
||||
func (daemon *Daemon) verifyContainerSettings(hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) {
|
||||
func (daemon *Daemon) verifyContainerSettings(ctx context.Context, hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) {
|
||||
|
||||
// First perform verification of settings common across all platforms.
|
||||
if config != nil {
|
||||
|
@ -1131,7 +1129,7 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *runconfig.HostConfig,
|
|||
}
|
||||
|
||||
// Now do platform-specific verification
|
||||
return verifyPlatformContainerSettings(daemon, hostConfig, config)
|
||||
return verifyPlatformContainerSettings(ctx, daemon, hostConfig, config)
|
||||
}
|
||||
|
||||
func configureVolumes(config *Config) (*store.VolumeStore, error) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/pkg/graphdb"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/truncindex"
|
||||
|
@ -92,32 +93,34 @@ func TestGet(t *testing.T) {
|
|||
containerGraphDB: graph,
|
||||
}
|
||||
|
||||
if container, _ := daemon.Get("3cdbd1aa394fd68559fd1441d6eff2ab7c1e6363582c82febfaa8045df3bd8de"); container != c2 {
|
||||
ctx := context.Background()
|
||||
|
||||
if container, _ := daemon.Get(ctx, "3cdbd1aa394fd68559fd1441d6eff2ab7c1e6363582c82febfaa8045df3bd8de"); container != c2 {
|
||||
t.Fatal("Should explicitly match full container IDs")
|
||||
}
|
||||
|
||||
if container, _ := daemon.Get("75fb0b8009"); container != c4 {
|
||||
if container, _ := daemon.Get(ctx, "75fb0b8009"); container != c4 {
|
||||
t.Fatal("Should match a partial ID")
|
||||
}
|
||||
|
||||
if container, _ := daemon.Get("drunk_hawking"); container != c2 {
|
||||
if container, _ := daemon.Get(ctx, "drunk_hawking"); container != c2 {
|
||||
t.Fatal("Should match a full name")
|
||||
}
|
||||
|
||||
// c3.Name is a partial match for both c3.ID and c2.ID
|
||||
if c, _ := daemon.Get("3cdbd1aa"); c != c3 {
|
||||
if c, _ := daemon.Get(ctx, "3cdbd1aa"); c != c3 {
|
||||
t.Fatal("Should match a full name even though it collides with another container's ID")
|
||||
}
|
||||
|
||||
if container, _ := daemon.Get("d22d69a2b896"); container != c5 {
|
||||
if container, _ := daemon.Get(ctx, "d22d69a2b896"); container != c5 {
|
||||
t.Fatal("Should match a container where the provided prefix is an exact match to the it's name, and is also a prefix for it's ID")
|
||||
}
|
||||
|
||||
if _, err := daemon.Get("3cdbd1"); err == nil {
|
||||
if _, err := daemon.Get(ctx, "3cdbd1"); err == nil {
|
||||
t.Fatal("Should return an error when provided a prefix that partially matches multiple container ID's")
|
||||
}
|
||||
|
||||
if _, err := daemon.Get("nothing"); err == nil {
|
||||
if _, err := daemon.Get(ctx, "nothing"); err == nil {
|
||||
t.Fatal("Should return an error when provided a prefix that is neither a name or a partial match to an ID")
|
||||
}
|
||||
|
||||
|
@ -486,13 +489,15 @@ func TestRemoveLocalVolumesFollowingSymlinks(t *testing.T) {
|
|||
t.Fatalf("Expected 1 volume mounted, was 0\n")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
m := c.MountPoints["/vol1"]
|
||||
_, err = daemon.VolumeCreate(m.Name, m.Driver, nil)
|
||||
_, err = daemon.VolumeCreate(ctx, m.Name, m.Driver, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := daemon.VolumeRm(m.Name); err != nil {
|
||||
if err := daemon.VolumeRm(ctx, m.Name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/autogen/dockerversion"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/docker/docker/pkg/fileutils"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
|
@ -114,12 +115,12 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *runconfig.HostConfig, a
|
|||
|
||||
// verifyPlatformContainerSettings performs platform-specific validation of the
|
||||
// hostconfig and config structures.
|
||||
func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) {
|
||||
func verifyPlatformContainerSettings(ctx context.Context, daemon *Daemon, hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) {
|
||||
warnings := []string{}
|
||||
sysInfo := sysinfo.New(true)
|
||||
|
||||
if hostConfig.LxcConf.Len() > 0 && !strings.Contains(daemon.ExecutionDriver().Name(), "lxc") {
|
||||
return warnings, fmt.Errorf("Cannot use --lxc-conf with execdriver: %s", daemon.ExecutionDriver().Name())
|
||||
if hostConfig.LxcConf.Len() > 0 && !strings.Contains(daemon.ExecutionDriver(ctx).Name(), "lxc") {
|
||||
return warnings, fmt.Errorf("Cannot use --lxc-conf with execdriver: %s", daemon.ExecutionDriver(ctx).Name())
|
||||
}
|
||||
|
||||
// memory subsystem checks and adjustments
|
||||
|
@ -484,12 +485,12 @@ func setupInitLayer(initLayer string) error {
|
|||
|
||||
// NetworkAPIRouter implements a feature for server-experimental,
|
||||
// directly calling into libnetwork.
|
||||
func (daemon *Daemon) NetworkAPIRouter() func(w http.ResponseWriter, req *http.Request) {
|
||||
func (daemon *Daemon) NetworkAPIRouter(ctx context.Context) func(w http.ResponseWriter, req *http.Request) {
|
||||
return nwapi.NewHTTPHandler(daemon.netController)
|
||||
}
|
||||
|
||||
// registerLinks writes the links to a file.
|
||||
func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig.HostConfig) error {
|
||||
func (daemon *Daemon) registerLinks(ctx context.Context, container *Container, hostConfig *runconfig.HostConfig) error {
|
||||
if hostConfig == nil || hostConfig.Links == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -499,14 +500,14 @@ func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig.
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
child, err := daemon.Get(name)
|
||||
child, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
//An error from daemon.Get() means this name could not be found
|
||||
return fmt.Errorf("Could not get container for %s", name)
|
||||
}
|
||||
for child.hostConfig.NetworkMode.IsContainer() {
|
||||
parts := strings.SplitN(string(child.hostConfig.NetworkMode), ":", 2)
|
||||
child, err = daemon.Get(parts[1])
|
||||
child, err = daemon.Get(ctx, parts[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not get container for %s", parts[1])
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"syscall"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
// register the windows graph driver
|
||||
_ "github.com/docker/docker/daemon/graphdriver/windows"
|
||||
|
@ -47,7 +48,7 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *runconfig.HostConfig, a
|
|||
|
||||
// verifyPlatformContainerSettings performs platform-specific validation of the
|
||||
// hostconfig and config structures.
|
||||
func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) {
|
||||
func verifyPlatformContainerSettings(ctx context.Context, daemon *Daemon, hostConfig *runconfig.HostConfig, config *runconfig.Config) ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
@ -104,7 +105,7 @@ func initNetworkController(config *Config) (libnetwork.NetworkController, error)
|
|||
|
||||
// registerLinks sets up links between containers and writes the
|
||||
// configuration out for persistence.
|
||||
func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig.HostConfig) error {
|
||||
func (daemon *Daemon) registerLinks(ctx context.Context, container *Container, hostConfig *runconfig.HostConfig) error {
|
||||
// TODO Windows. Factored out for network modes. There may be more
|
||||
// refactoring required here.
|
||||
|
||||
|
@ -117,7 +118,7 @@ func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig.
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
child, err := daemon.Get(name)
|
||||
child, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
//An error from daemon.Get() means this name could not be found
|
||||
return fmt.Errorf("Could not get container for %s", name)
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
derr "github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/volume/store"
|
||||
|
@ -19,8 +21,8 @@ type ContainerRmConfig struct {
|
|||
// is returned if the container is not found, or if the remove
|
||||
// fails. If the remove succeeds, the container name is released, and
|
||||
// network links are removed.
|
||||
func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerRm(ctx context.Context, name string, config *ContainerRmConfig) error {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -43,9 +45,9 @@ func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error
|
|||
return err
|
||||
}
|
||||
|
||||
parentContainer, _ := daemon.Get(pe.ID())
|
||||
parentContainer, _ := daemon.Get(ctx, pe.ID())
|
||||
if parentContainer != nil {
|
||||
if err := parentContainer.updateNetwork(); err != nil {
|
||||
if err := parentContainer.updateNetwork(ctx); err != nil {
|
||||
logrus.Debugf("Could not update network to remove link %s: %v", n, err)
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +55,7 @@ func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error
|
|||
return nil
|
||||
}
|
||||
|
||||
if err := daemon.rm(container, config.ForceRemove); err != nil {
|
||||
if err := daemon.rm(ctx, container, config.ForceRemove); err != nil {
|
||||
// return derr.ErrorCodeCantDestroy.WithArgs(name, utils.GetErrorMessage(err))
|
||||
return err
|
||||
}
|
||||
|
@ -66,12 +68,12 @@ func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error
|
|||
}
|
||||
|
||||
// Destroy unregisters a container from the daemon and cleanly removes its contents from the filesystem.
|
||||
func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) {
|
||||
func (daemon *Daemon) rm(ctx context.Context, container *Container, forceRemove bool) (err error) {
|
||||
if container.IsRunning() {
|
||||
if !forceRemove {
|
||||
return derr.ErrorCodeRmRunning
|
||||
}
|
||||
if err := container.Kill(); err != nil {
|
||||
if err := container.Kill(ctx); err != nil {
|
||||
return derr.ErrorCodeRmFailed.WithArgs(err)
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +94,7 @@ func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) {
|
|||
|
||||
defer container.resetRemovalInProgress()
|
||||
|
||||
if err = container.Stop(3); err != nil {
|
||||
if err = container.Stop(ctx, 3); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -113,7 +115,7 @@ func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) {
|
|||
daemon.idIndex.Delete(container.ID)
|
||||
daemon.containers.Delete(container.ID)
|
||||
os.RemoveAll(container.root)
|
||||
container.logEvent("destroy")
|
||||
container.logEvent(ctx, "destroy")
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -142,14 +144,14 @@ func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) {
|
|||
daemon.idIndex.Delete(container.ID)
|
||||
daemon.containers.Delete(container.ID)
|
||||
|
||||
container.logEvent("destroy")
|
||||
container.logEvent(ctx, "destroy")
|
||||
return nil
|
||||
}
|
||||
|
||||
// VolumeRm removes the volume with the given name.
|
||||
// If the volume is referenced by a container it is not removed
|
||||
// This is called directly from the remote API
|
||||
func (daemon *Daemon) VolumeRm(name string) error {
|
||||
func (daemon *Daemon) VolumeRm(ctx context.Context, name string) error {
|
||||
v, err := daemon.volumes.Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -4,6 +4,8 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/pkg/pubsub"
|
||||
)
|
||||
|
@ -44,9 +46,9 @@ func (e *Events) Evict(l chan interface{}) {
|
|||
|
||||
// Log broadcasts event to listeners. Each listener has 100 millisecond for
|
||||
// receiving event or it will be skipped.
|
||||
func (e *Events) Log(action, id, from string) {
|
||||
func (e *Events) Log(ctx context.Context, action, id, from string) {
|
||||
now := time.Now().UTC()
|
||||
jm := &jsonmessage.JSONMessage{Status: action, ID: id, From: from, Time: now.Unix(), TimeNano: now.UnixNano()}
|
||||
jm := &jsonmessage.JSONMessage{RequestID: ctx.RequestID(), Status: action, ID: id, From: from, Time: now.Unix(), TimeNano: now.UnixNano()}
|
||||
e.mu.Lock()
|
||||
if len(e.events) == cap(e.events) {
|
||||
// discard oldest event
|
||||
|
|
|
@ -5,10 +5,12 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
)
|
||||
|
||||
func TestEventsLog(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
e := New()
|
||||
_, l1 := e.Subscribe()
|
||||
_, l2 := e.Subscribe()
|
||||
|
@ -18,7 +20,7 @@ func TestEventsLog(t *testing.T) {
|
|||
if count != 2 {
|
||||
t.Fatalf("Must be 2 subscribers, got %d", count)
|
||||
}
|
||||
e.Log("test", "cont", "image")
|
||||
e.Log(ctx, "test", "cont", "image")
|
||||
select {
|
||||
case msg := <-l1:
|
||||
jmsg, ok := msg.(*jsonmessage.JSONMessage)
|
||||
|
@ -64,13 +66,14 @@ func TestEventsLog(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestEventsLogTimeout(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
e := New()
|
||||
_, l := e.Subscribe()
|
||||
defer e.Evict(l)
|
||||
|
||||
c := make(chan struct{})
|
||||
go func() {
|
||||
e.Log("test", "cont", "image")
|
||||
e.Log(ctx, "test", "cont", "image")
|
||||
close(c)
|
||||
}()
|
||||
|
||||
|
@ -82,13 +85,14 @@ func TestEventsLogTimeout(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLogEvents(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
e := New()
|
||||
|
||||
for i := 0; i < eventsLimit+16; i++ {
|
||||
action := fmt.Sprintf("action_%d", i)
|
||||
id := fmt.Sprintf("cont_%d", i)
|
||||
from := fmt.Sprintf("image_%d", i)
|
||||
e.Log(action, id, from)
|
||||
e.Log(ctx, action, id, from)
|
||||
}
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
current, l := e.Subscribe()
|
||||
|
@ -97,7 +101,7 @@ func TestLogEvents(t *testing.T) {
|
|||
action := fmt.Sprintf("action_%d", num)
|
||||
id := fmt.Sprintf("cont_%d", num)
|
||||
from := fmt.Sprintf("image_%d", num)
|
||||
e.Log(action, id, from)
|
||||
e.Log(ctx, action, id, from)
|
||||
}
|
||||
if len(e.events) != eventsLimit {
|
||||
t.Fatalf("Must be %d events, got %d", eventsLimit, len(e.events))
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
derr "github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/pkg/broadcastwriter"
|
||||
|
@ -117,8 +118,8 @@ func (d *Daemon) unregisterExecCommand(ExecConfig *ExecConfig) {
|
|||
d.execCommands.Delete(ExecConfig.ID)
|
||||
}
|
||||
|
||||
func (d *Daemon) getActiveContainer(name string) (*Container, error) {
|
||||
container, err := d.Get(name)
|
||||
func (d *Daemon) getActiveContainer(ctx context.Context, name string) (*Container, error) {
|
||||
container, err := d.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -133,13 +134,13 @@ func (d *Daemon) getActiveContainer(name string) (*Container, error) {
|
|||
}
|
||||
|
||||
// ContainerExecCreate sets up an exec in a running container.
|
||||
func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, error) {
|
||||
func (d *Daemon) ContainerExecCreate(ctx context.Context, config *runconfig.ExecConfig) (string, error) {
|
||||
// Not all drivers support Exec (LXC for example)
|
||||
if err := checkExecSupport(d.execDriver.Name()); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
container, err := d.getActiveContainer(config.Container)
|
||||
container, err := d.getActiveContainer(ctx, config.Container)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -174,14 +175,14 @@ func (d *Daemon) ContainerExecCreate(config *runconfig.ExecConfig) (string, erro
|
|||
|
||||
d.registerExecCommand(ExecConfig)
|
||||
|
||||
container.logEvent("exec_create: " + ExecConfig.ProcessConfig.Entrypoint + " " + strings.Join(ExecConfig.ProcessConfig.Arguments, " "))
|
||||
container.logEvent(ctx, "exec_create: "+ExecConfig.ProcessConfig.Entrypoint+" "+strings.Join(ExecConfig.ProcessConfig.Arguments, " "))
|
||||
|
||||
return ExecConfig.ID, nil
|
||||
}
|
||||
|
||||
// ContainerExecStart starts a previously set up exec instance. The
|
||||
// std streams are set up.
|
||||
func (d *Daemon) ContainerExecStart(execName string, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) error {
|
||||
func (d *Daemon) ContainerExecStart(ctx context.Context, execName string, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) error {
|
||||
var (
|
||||
cStdin io.ReadCloser
|
||||
cStdout, cStderr io.Writer
|
||||
|
@ -207,7 +208,7 @@ func (d *Daemon) ContainerExecStart(execName string, stdin io.ReadCloser, stdout
|
|||
logrus.Debugf("starting exec command %s in container %s", ExecConfig.ID, ExecConfig.Container.ID)
|
||||
container := ExecConfig.Container
|
||||
|
||||
container.logEvent("exec_start: " + ExecConfig.ProcessConfig.Entrypoint + " " + strings.Join(ExecConfig.ProcessConfig.Arguments, " "))
|
||||
container.logEvent(ctx, "exec_start: "+ExecConfig.ProcessConfig.Entrypoint+" "+strings.Join(ExecConfig.ProcessConfig.Arguments, " "))
|
||||
|
||||
if ExecConfig.OpenStdin {
|
||||
r, w := io.Pipe()
|
||||
|
@ -243,7 +244,7 @@ func (d *Daemon) ContainerExecStart(execName string, stdin io.ReadCloser, stdout
|
|||
// the exitStatus) even after the cmd is done running.
|
||||
|
||||
go func() {
|
||||
if err := container.exec(ExecConfig); err != nil {
|
||||
if err := container.exec(ctx, ExecConfig); err != nil {
|
||||
execErr <- derr.ErrorCodeExecCantRun.WithArgs(execName, container.ID, err)
|
||||
}
|
||||
}()
|
||||
|
@ -267,11 +268,11 @@ func (d *Daemon) ContainerExecStart(execName string, stdin io.ReadCloser, stdout
|
|||
}
|
||||
|
||||
// Exec calls the underlying exec driver to run
|
||||
func (d *Daemon) Exec(c *Container, ExecConfig *ExecConfig, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (int, error) {
|
||||
func (d *Daemon) Exec(ctx context.Context, c *Container, ExecConfig *ExecConfig, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (int, error) {
|
||||
hooks := execdriver.Hooks{
|
||||
Start: startCallback,
|
||||
}
|
||||
exitStatus, err := d.execDriver.Exec(c.command, ExecConfig.ProcessConfig, pipes, hooks)
|
||||
exitStatus, err := d.execDriver.Exec(ctx, c.command, ExecConfig.ProcessConfig, pipes, hooks)
|
||||
|
||||
// On err, make sure we don't leave ExitCode at zero
|
||||
if err != nil && exitStatus == 0 {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
// TODO Windows: Factor out ulimit
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/pkg/ulimit"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
|
@ -29,7 +30,7 @@ var (
|
|||
// through PreStart, Start and PostStop events.
|
||||
// Callbacks are provided a processConfig pointer and the pid of the child.
|
||||
// The channel will be used to notify the OOM events.
|
||||
type DriverCallback func(processConfig *ProcessConfig, pid int, chOOM <-chan struct{}) error
|
||||
type DriverCallback func(ctx context.Context, processConfig *ProcessConfig, pid int, chOOM <-chan struct{}) error
|
||||
|
||||
// Hooks is a struct containing function pointers to callbacks
|
||||
// used by any execdriver implementation exploiting hooks capabilities
|
||||
|
@ -69,11 +70,11 @@ type ExitStatus struct {
|
|||
type Driver interface {
|
||||
// Run executes the process, blocks until the process exits and returns
|
||||
// the exit code. It's the last stage on Docker side for running a container.
|
||||
Run(c *Command, pipes *Pipes, hooks Hooks) (ExitStatus, error)
|
||||
Run(ctx context.Context, c *Command, pipes *Pipes, hooks Hooks) (ExitStatus, error)
|
||||
|
||||
// Exec executes the process in an existing container, blocks until the
|
||||
// process exits and returns the exit code.
|
||||
Exec(c *Command, processConfig *ProcessConfig, pipes *Pipes, hooks Hooks) (int, error)
|
||||
Exec(ctx context.Context, c *Command, processConfig *ProcessConfig, pipes *Pipes, hooks Hooks) (int, error)
|
||||
|
||||
// Kill sends signals to process in container.
|
||||
Kill(c *Command, sig int) error
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/pkg/stringutils"
|
||||
sysinfo "github.com/docker/docker/pkg/system"
|
||||
|
@ -125,7 +126,7 @@ func killNetNsProc(proc *os.Process) {
|
|||
|
||||
// Run implements the exec driver Driver interface,
|
||||
// it calls 'exec.Cmd' to launch lxc commands to run a container.
|
||||
func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
||||
func (d *Driver) Run(ctx context.Context, c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
||||
var (
|
||||
term execdriver.Terminal
|
||||
err error
|
||||
|
@ -329,7 +330,7 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
|
|||
|
||||
if hooks.Start != nil {
|
||||
logrus.Debugf("Invoking startCallback")
|
||||
hooks.Start(&c.ProcessConfig, pid, oomKillNotification)
|
||||
hooks.Start(ctx, &c.ProcessConfig, pid, oomKillNotification)
|
||||
|
||||
}
|
||||
|
||||
|
@ -871,7 +872,7 @@ func (t *TtyConsole) Close() error {
|
|||
|
||||
// Exec implements the exec driver Driver interface,
|
||||
// it is not implemented by lxc.
|
||||
func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
|
||||
func (d *Driver) Exec(ctx context.Context, c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
|
||||
return -1, ErrExec
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/opencontainers/runc/libcontainer/apparmor"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
|
@ -18,7 +19,7 @@ import (
|
|||
|
||||
// createContainer populates and configures the container type with the
|
||||
// data provided by the execdriver.Command
|
||||
func (d *Driver) createContainer(c *execdriver.Command, hooks execdriver.Hooks) (*configs.Config, error) {
|
||||
func (d *Driver) createContainer(ctx context.Context, c *execdriver.Command, hooks execdriver.Hooks) (*configs.Config, error) {
|
||||
container := execdriver.InitContainer(c)
|
||||
|
||||
if err := d.createIpc(container, c); err != nil {
|
||||
|
@ -33,7 +34,7 @@ func (d *Driver) createContainer(c *execdriver.Command, hooks execdriver.Hooks)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := d.createNetwork(container, c, hooks); err != nil {
|
||||
if err := d.createNetwork(ctx, container, c, hooks); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -113,7 +114,7 @@ func generateIfaceName() (string, error) {
|
|||
return "", errors.New("Failed to find name for new interface")
|
||||
}
|
||||
|
||||
func (d *Driver) createNetwork(container *configs.Config, c *execdriver.Command, hooks execdriver.Hooks) error {
|
||||
func (d *Driver) createNetwork(ctx context.Context, container *configs.Config, c *execdriver.Command, hooks execdriver.Hooks) error {
|
||||
if c.Network == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -150,7 +151,7 @@ func (d *Driver) createNetwork(container *configs.Config, c *execdriver.Command,
|
|||
// non-blocking and return the correct result when read.
|
||||
chOOM := make(chan struct{})
|
||||
close(chOOM)
|
||||
if err := fnHook(&c.ProcessConfig, s.Pid, chOOM); err != nil {
|
||||
if err := fnHook(ctx, &c.ProcessConfig, s.Pid, chOOM); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/pkg/pools"
|
||||
|
@ -131,9 +132,9 @@ type execOutput struct {
|
|||
|
||||
// Run implements the exec driver Driver interface,
|
||||
// it calls libcontainer APIs to run a container.
|
||||
func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
||||
func (d *Driver) Run(ctx context.Context, c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
||||
// take the Command and populate the libcontainer.Config from it
|
||||
container, err := d.createContainer(c, hooks)
|
||||
container, err := d.createContainer(ctx, c, hooks)
|
||||
if err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
|
@ -174,7 +175,7 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
|
|||
p.Wait()
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
hooks.Start(&c.ProcessConfig, pid, oom)
|
||||
hooks.Start(ctx, &c.ProcessConfig, pid, oom)
|
||||
}
|
||||
|
||||
waitF := p.Wait
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"os/exec"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
// Blank import 'nsenter' so that init in that package will call c
|
||||
|
@ -19,7 +20,7 @@ import (
|
|||
|
||||
// Exec implements the exec driver Driver interface,
|
||||
// it calls libcontainer APIs to execute a container.
|
||||
func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
|
||||
func (d *Driver) Exec(ctx context.Context, c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
|
||||
active := d.activeContainers[c.ID]
|
||||
if active == nil {
|
||||
return -1, fmt.Errorf("No active container exists with ID %s", c.ID)
|
||||
|
@ -57,7 +58,7 @@ func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo
|
|||
// non-blocking and return the correct result when read.
|
||||
chOOM := make(chan struct{})
|
||||
close(chOOM)
|
||||
hooks.Start(&c.ProcessConfig, pid, chOOM)
|
||||
hooks.Start(ctx, &c.ProcessConfig, pid, chOOM)
|
||||
}
|
||||
|
||||
ps, err := p.Wait()
|
||||
|
|
|
@ -7,12 +7,13 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/microsoft/hcsshim"
|
||||
)
|
||||
|
||||
// Exec implements the exec driver Driver interface.
|
||||
func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
|
||||
func (d *Driver) Exec(ctx context.Context, c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
|
||||
|
||||
var (
|
||||
term execdriver.Terminal
|
||||
|
@ -74,7 +75,7 @@ func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo
|
|||
// non-blocking and return the correct result when read.
|
||||
chOOM := make(chan struct{})
|
||||
close(chOOM)
|
||||
hooks.Start(&c.ProcessConfig, int(pid), chOOM)
|
||||
hooks.Start(ctx, &c.ProcessConfig, int(pid), chOOM)
|
||||
}
|
||||
|
||||
if exitCode, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid); err != nil {
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"syscall"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/microsoft/hcsshim"
|
||||
)
|
||||
|
@ -79,7 +80,7 @@ type containerInit struct {
|
|||
const defaultOwner = "docker"
|
||||
|
||||
// Run implements the exec driver Driver interface
|
||||
func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
||||
func (d *Driver) Run(ctx context.Context, c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
||||
|
||||
var (
|
||||
term execdriver.Terminal
|
||||
|
@ -298,7 +299,7 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
|
|||
// non-blocking and return the correct result when read.
|
||||
chOOM := make(chan struct{})
|
||||
close(chOOM)
|
||||
hooks.Start(&c.ProcessConfig, int(pid), chOOM)
|
||||
hooks.Start(ctx, &c.ProcessConfig, int(pid), chOOM)
|
||||
}
|
||||
|
||||
var exitCode int32
|
||||
|
|
|
@ -3,18 +3,19 @@ package daemon
|
|||
import (
|
||||
"io"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
derr "github.com/docker/docker/errors"
|
||||
)
|
||||
|
||||
// ContainerExport writes the contents of the container to the given
|
||||
// writer. An error is returned if the container cannot be found.
|
||||
func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerExport(ctx context.Context, name string, out io.Writer) error {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := container.export()
|
||||
data, err := container.export(ctx)
|
||||
if err != nil {
|
||||
return derr.ErrorCodeExportFailed.WithArgs(name, err)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/context"
|
||||
derr "github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/graph/tags"
|
||||
"github.com/docker/docker/image"
|
||||
|
@ -50,10 +51,10 @@ import (
|
|||
// FIXME: remove ImageDelete's dependency on Daemon, then move to the graph
|
||||
// package. This would require that we no longer need the daemon to determine
|
||||
// whether images are being used by a stopped or running container.
|
||||
func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.ImageDelete, error) {
|
||||
func (daemon *Daemon) ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDelete, error) {
|
||||
records := []types.ImageDelete{}
|
||||
|
||||
img, err := daemon.Repositories().LookupImage(imageRef)
|
||||
img, err := daemon.Repositories(ctx).LookupImage(imageRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -64,8 +65,8 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
// first. We can only remove this reference if either force is
|
||||
// true, there are multiple repository references to this
|
||||
// image, or there are no containers using the given reference.
|
||||
if !(force || daemon.imageHasMultipleRepositoryReferences(img.ID)) {
|
||||
if container := daemon.getContainerUsingImage(img.ID); container != nil {
|
||||
if !(force || daemon.imageHasMultipleRepositoryReferences(ctx, img.ID)) {
|
||||
if container := daemon.getContainerUsingImage(ctx, img.ID); container != nil {
|
||||
// If we removed the repository reference then
|
||||
// this image would remain "dangling" and since
|
||||
// we really want to avoid that the client must
|
||||
|
@ -74,14 +75,14 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
}
|
||||
}
|
||||
|
||||
parsedRef, err := daemon.removeImageRef(imageRef)
|
||||
parsedRef, err := daemon.removeImageRef(ctx, imageRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
untaggedRecord := types.ImageDelete{Untagged: parsedRef}
|
||||
|
||||
daemon.EventsService.Log("untag", img.ID, "")
|
||||
daemon.EventsService.Log(ctx, "untag", img.ID, "")
|
||||
records = append(records, untaggedRecord)
|
||||
|
||||
removedRepositoryRef = true
|
||||
|
@ -90,21 +91,21 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
// repository reference to the image then we will want to
|
||||
// remove that reference.
|
||||
// FIXME: Is this the behavior we want?
|
||||
repoRefs := daemon.Repositories().ByID()[img.ID]
|
||||
repoRefs := daemon.Repositories(ctx).ByID()[img.ID]
|
||||
if len(repoRefs) == 1 {
|
||||
parsedRef, err := daemon.removeImageRef(repoRefs[0])
|
||||
parsedRef, err := daemon.removeImageRef(ctx, repoRefs[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
untaggedRecord := types.ImageDelete{Untagged: parsedRef}
|
||||
|
||||
daemon.EventsService.Log("untag", img.ID, "")
|
||||
daemon.EventsService.Log(ctx, "untag", img.ID, "")
|
||||
records = append(records, untaggedRecord)
|
||||
}
|
||||
}
|
||||
|
||||
return records, daemon.imageDeleteHelper(img, &records, force, prune, removedRepositoryRef)
|
||||
return records, daemon.imageDeleteHelper(ctx, img, &records, force, prune, removedRepositoryRef)
|
||||
}
|
||||
|
||||
// isImageIDPrefix returns whether the given possiblePrefix is a prefix of the
|
||||
|
@ -115,14 +116,14 @@ func isImageIDPrefix(imageID, possiblePrefix string) bool {
|
|||
|
||||
// imageHasMultipleRepositoryReferences returns whether there are multiple
|
||||
// repository references to the given imageID.
|
||||
func (daemon *Daemon) imageHasMultipleRepositoryReferences(imageID string) bool {
|
||||
return len(daemon.Repositories().ByID()[imageID]) > 1
|
||||
func (daemon *Daemon) imageHasMultipleRepositoryReferences(ctx context.Context, imageID string) bool {
|
||||
return len(daemon.Repositories(ctx).ByID()[imageID]) > 1
|
||||
}
|
||||
|
||||
// getContainerUsingImage returns a container that was created using the given
|
||||
// imageID. Returns nil if there is no such container.
|
||||
func (daemon *Daemon) getContainerUsingImage(imageID string) *Container {
|
||||
for _, container := range daemon.List() {
|
||||
func (daemon *Daemon) getContainerUsingImage(ctx context.Context, imageID string) *Container {
|
||||
for _, container := range daemon.List(ctx) {
|
||||
if container.ImageID == imageID {
|
||||
return container
|
||||
}
|
||||
|
@ -136,7 +137,7 @@ func (daemon *Daemon) getContainerUsingImage(imageID string) *Container {
|
|||
// repositoryRef must not be an image ID but a repository name followed by an
|
||||
// optional tag or digest reference. If tag or digest is omitted, the default
|
||||
// tag is used. Returns the resolved image reference and an error.
|
||||
func (daemon *Daemon) removeImageRef(repositoryRef string) (string, error) {
|
||||
func (daemon *Daemon) removeImageRef(ctx context.Context, repositoryRef string) (string, error) {
|
||||
repository, ref := parsers.ParseRepositoryTag(repositoryRef)
|
||||
if ref == "" {
|
||||
ref = tags.DefaultTag
|
||||
|
@ -145,7 +146,7 @@ func (daemon *Daemon) removeImageRef(repositoryRef string) (string, error) {
|
|||
// Ignore the boolean value returned, as far as we're concerned, this
|
||||
// is an idempotent operation and it's okay if the reference didn't
|
||||
// exist in the first place.
|
||||
_, err := daemon.Repositories().Delete(repository, ref)
|
||||
_, err := daemon.Repositories(ctx).Delete(repository, ref)
|
||||
|
||||
return utils.ImageReference(repository, ref), err
|
||||
}
|
||||
|
@ -155,18 +156,18 @@ func (daemon *Daemon) removeImageRef(repositoryRef string) (string, error) {
|
|||
// on the first encountered error. Removed references are logged to this
|
||||
// daemon's event service. An "Untagged" types.ImageDelete is added to the
|
||||
// given list of records.
|
||||
func (daemon *Daemon) removeAllReferencesToImageID(imgID string, records *[]types.ImageDelete) error {
|
||||
imageRefs := daemon.Repositories().ByID()[imgID]
|
||||
func (daemon *Daemon) removeAllReferencesToImageID(ctx context.Context, imgID string, records *[]types.ImageDelete) error {
|
||||
imageRefs := daemon.Repositories(ctx).ByID()[imgID]
|
||||
|
||||
for _, imageRef := range imageRefs {
|
||||
parsedRef, err := daemon.removeImageRef(imageRef)
|
||||
parsedRef, err := daemon.removeImageRef(ctx, imageRef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
untaggedRecord := types.ImageDelete{Untagged: parsedRef}
|
||||
|
||||
daemon.EventsService.Log("untag", imgID, "")
|
||||
daemon.EventsService.Log(ctx, "untag", imgID, "")
|
||||
*records = append(*records, untaggedRecord)
|
||||
}
|
||||
|
||||
|
@ -203,11 +204,11 @@ func (idc *imageDeleteConflict) Error() string {
|
|||
// conflict is encountered, it will be returned immediately without deleting
|
||||
// the image. If quiet is true, any encountered conflicts will be ignored and
|
||||
// the function will return nil immediately without deleting the image.
|
||||
func (daemon *Daemon) imageDeleteHelper(img *image.Image, records *[]types.ImageDelete, force, prune, quiet bool) error {
|
||||
func (daemon *Daemon) imageDeleteHelper(ctx context.Context, img *image.Image, records *[]types.ImageDelete, force, prune, quiet bool) error {
|
||||
// First, determine if this image has any conflicts. Ignore soft conflicts
|
||||
// if force is true.
|
||||
if conflict := daemon.checkImageDeleteConflict(img, force); conflict != nil {
|
||||
if quiet && !daemon.imageIsDangling(img) {
|
||||
if conflict := daemon.checkImageDeleteConflict(ctx, img, force); conflict != nil {
|
||||
if quiet && !daemon.imageIsDangling(ctx, img) {
|
||||
// Ignore conflicts UNLESS the image is "dangling" in
|
||||
// which case we want the user to know.
|
||||
return nil
|
||||
|
@ -219,15 +220,15 @@ func (daemon *Daemon) imageDeleteHelper(img *image.Image, records *[]types.Image
|
|||
}
|
||||
|
||||
// Delete all repository tag/digest references to this image.
|
||||
if err := daemon.removeAllReferencesToImageID(img.ID, records); err != nil {
|
||||
if err := daemon.removeAllReferencesToImageID(ctx, img.ID, records); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := daemon.Graph().Delete(img.ID); err != nil {
|
||||
if err := daemon.Graph(ctx).Delete(img.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
daemon.EventsService.Log("delete", img.ID, "")
|
||||
daemon.EventsService.Log(ctx, "delete", img.ID, "")
|
||||
*records = append(*records, types.ImageDelete{Deleted: img.ID})
|
||||
|
||||
if !prune || img.Parent == "" {
|
||||
|
@ -237,14 +238,14 @@ func (daemon *Daemon) imageDeleteHelper(img *image.Image, records *[]types.Image
|
|||
// We need to prune the parent image. This means delete it if there are
|
||||
// no tags/digests referencing it and there are no containers using it (
|
||||
// either running or stopped).
|
||||
parentImg, err := daemon.Graph().Get(img.Parent)
|
||||
parentImg, err := daemon.Graph(ctx).Get(img.Parent)
|
||||
if err != nil {
|
||||
return derr.ErrorCodeImgNoParent.WithArgs(err)
|
||||
}
|
||||
|
||||
// Do not force prunings, but do so quietly (stopping on any encountered
|
||||
// conflicts).
|
||||
return daemon.imageDeleteHelper(parentImg, records, false, true, true)
|
||||
return daemon.imageDeleteHelper(ctx, parentImg, records, false, true, true)
|
||||
}
|
||||
|
||||
// checkImageDeleteConflict determines whether there are any conflicts
|
||||
|
@ -253,9 +254,9 @@ func (daemon *Daemon) imageDeleteHelper(img *image.Image, records *[]types.Image
|
|||
// using the image. A soft conflict is any tags/digest referencing the given
|
||||
// image or any stopped container using the image. If ignoreSoftConflicts is
|
||||
// true, this function will not check for soft conflict conditions.
|
||||
func (daemon *Daemon) checkImageDeleteConflict(img *image.Image, ignoreSoftConflicts bool) *imageDeleteConflict {
|
||||
func (daemon *Daemon) checkImageDeleteConflict(ctx context.Context, img *image.Image, ignoreSoftConflicts bool) *imageDeleteConflict {
|
||||
// Check for hard conflicts first.
|
||||
if conflict := daemon.checkImageDeleteHardConflict(img); conflict != nil {
|
||||
if conflict := daemon.checkImageDeleteHardConflict(ctx, img); conflict != nil {
|
||||
return conflict
|
||||
}
|
||||
|
||||
|
@ -265,12 +266,12 @@ func (daemon *Daemon) checkImageDeleteConflict(img *image.Image, ignoreSoftConfl
|
|||
return nil
|
||||
}
|
||||
|
||||
return daemon.checkImageDeleteSoftConflict(img)
|
||||
return daemon.checkImageDeleteSoftConflict(ctx, img)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) checkImageDeleteHardConflict(img *image.Image) *imageDeleteConflict {
|
||||
func (daemon *Daemon) checkImageDeleteHardConflict(ctx context.Context, img *image.Image) *imageDeleteConflict {
|
||||
// Check if the image ID is being used by a pull or build.
|
||||
if daemon.Graph().IsHeld(img.ID) {
|
||||
if daemon.Graph(ctx).IsHeld(img.ID) {
|
||||
return &imageDeleteConflict{
|
||||
hard: true,
|
||||
imgID: img.ID,
|
||||
|
@ -279,7 +280,7 @@ func (daemon *Daemon) checkImageDeleteHardConflict(img *image.Image) *imageDelet
|
|||
}
|
||||
|
||||
// Check if the image has any descendent images.
|
||||
if daemon.Graph().HasChildren(img) {
|
||||
if daemon.Graph(ctx).HasChildren(img) {
|
||||
return &imageDeleteConflict{
|
||||
hard: true,
|
||||
imgID: img.ID,
|
||||
|
@ -288,7 +289,7 @@ func (daemon *Daemon) checkImageDeleteHardConflict(img *image.Image) *imageDelet
|
|||
}
|
||||
|
||||
// Check if any running container is using the image.
|
||||
for _, container := range daemon.List() {
|
||||
for _, container := range daemon.List(ctx) {
|
||||
if !container.IsRunning() {
|
||||
// Skip this until we check for soft conflicts later.
|
||||
continue
|
||||
|
@ -306,9 +307,9 @@ func (daemon *Daemon) checkImageDeleteHardConflict(img *image.Image) *imageDelet
|
|||
return nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) checkImageDeleteSoftConflict(img *image.Image) *imageDeleteConflict {
|
||||
func (daemon *Daemon) checkImageDeleteSoftConflict(ctx context.Context, img *image.Image) *imageDeleteConflict {
|
||||
// Check if any repository tags/digest reference this image.
|
||||
if daemon.Repositories().HasReferences(img) {
|
||||
if daemon.Repositories(ctx).HasReferences(img) {
|
||||
return &imageDeleteConflict{
|
||||
imgID: img.ID,
|
||||
message: "image is referenced in one or more repositories",
|
||||
|
@ -316,7 +317,7 @@ func (daemon *Daemon) checkImageDeleteSoftConflict(img *image.Image) *imageDelet
|
|||
}
|
||||
|
||||
// Check if any stopped containers reference this image.
|
||||
for _, container := range daemon.List() {
|
||||
for _, container := range daemon.List(ctx) {
|
||||
if container.IsRunning() {
|
||||
// Skip this as it was checked above in hard conflict conditions.
|
||||
continue
|
||||
|
@ -336,6 +337,6 @@ func (daemon *Daemon) checkImageDeleteSoftConflict(img *image.Image) *imageDelet
|
|||
// imageIsDangling returns whether the given image is "dangling" which means
|
||||
// that there are no repository references to the given image and it has no
|
||||
// child images.
|
||||
func (daemon *Daemon) imageIsDangling(img *image.Image) bool {
|
||||
return !(daemon.Repositories().HasReferences(img) || daemon.Graph().HasChildren(img))
|
||||
func (daemon *Daemon) imageIsDangling(ctx context.Context, img *image.Image) bool {
|
||||
return !(daemon.Repositories(ctx).HasReferences(img) || daemon.Graph(ctx).HasChildren(img))
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/autogen/dockerversion"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/pkg/fileutils"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/docker/docker/pkg/parsers/operatingsystem"
|
||||
|
@ -18,8 +19,8 @@ import (
|
|||
)
|
||||
|
||||
// SystemInfo returns information about the host server the daemon is running on.
|
||||
func (daemon *Daemon) SystemInfo() (*types.Info, error) {
|
||||
images := daemon.Graph().Map()
|
||||
func (daemon *Daemon) SystemInfo(ctx context.Context) (*types.Info, error) {
|
||||
images := daemon.Graph(ctx).Map()
|
||||
var imgcount int
|
||||
if images == nil {
|
||||
imgcount = 0
|
||||
|
@ -65,10 +66,10 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
|
|||
|
||||
v := &types.Info{
|
||||
ID: daemon.ID,
|
||||
Containers: len(daemon.List()),
|
||||
Containers: len(daemon.List(ctx)),
|
||||
Images: imgcount,
|
||||
Driver: daemon.GraphDriver().String(),
|
||||
DriverStatus: daemon.GraphDriver().Status(),
|
||||
Driver: daemon.GraphDriver(ctx).String(),
|
||||
DriverStatus: daemon.GraphDriver(ctx).Status(),
|
||||
IPv4Forwarding: !sysInfo.IPv4ForwardingDisabled,
|
||||
BridgeNfIptables: !sysInfo.BridgeNfCallIptablesDisabled,
|
||||
BridgeNfIP6tables: !sysInfo.BridgeNfCallIP6tablesDisabled,
|
||||
|
@ -76,7 +77,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
|
|||
NFd: fileutils.GetTotalUsedFds(),
|
||||
NGoroutines: runtime.NumGoroutine(),
|
||||
SystemTime: time.Now().Format(time.RFC3339Nano),
|
||||
ExecutionDriver: daemon.ExecutionDriver().Name(),
|
||||
ExecutionDriver: daemon.ExecutionDriver(ctx).Name(),
|
||||
LoggingDriver: daemon.defaultLogConfig.Type,
|
||||
NEventsListener: daemon.EventsService.SubscribersCount(),
|
||||
KernelVersion: kernelVersion,
|
||||
|
|
|
@ -5,13 +5,14 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/context"
|
||||
)
|
||||
|
||||
// ContainerInspect returns low-level information about a
|
||||
// container. Returns an error if the container cannot be found, or if
|
||||
// there is an error getting the data.
|
||||
func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error) {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerInspect(ctx context.Context, name string) (*types.ContainerJSON, error) {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -19,7 +20,7 @@ func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error
|
|||
container.Lock()
|
||||
defer container.Unlock()
|
||||
|
||||
base, err := daemon.getInspectData(container)
|
||||
base, err := daemon.getInspectData(ctx, container)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -30,8 +31,8 @@ func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error
|
|||
}
|
||||
|
||||
// ContainerInspect120 serializes the master version of a container into a json type.
|
||||
func (daemon *Daemon) ContainerInspect120(name string) (*types.ContainerJSON120, error) {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerInspect120(ctx context.Context, name string) (*types.ContainerJSON120, error) {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -39,7 +40,7 @@ func (daemon *Daemon) ContainerInspect120(name string) (*types.ContainerJSON120,
|
|||
container.Lock()
|
||||
defer container.Unlock()
|
||||
|
||||
base, err := daemon.getInspectData(container)
|
||||
base, err := daemon.getInspectData(ctx, container)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -53,11 +54,11 @@ func (daemon *Daemon) ContainerInspect120(name string) (*types.ContainerJSON120,
|
|||
return &types.ContainerJSON120{base, mountPoints, config}, nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSONBase, error) {
|
||||
func (daemon *Daemon) getInspectData(ctx context.Context, container *Container) (*types.ContainerJSONBase, error) {
|
||||
// make a copy to play with
|
||||
hostConfig := *container.hostConfig
|
||||
|
||||
if children, err := daemon.children(container.Name); err == nil {
|
||||
if children, err := daemon.children(ctx, container.Name); err == nil {
|
||||
for linkAlias, child := range children {
|
||||
hostConfig.Links = append(hostConfig.Links, fmt.Sprintf("%s:%s", child.Name, linkAlias))
|
||||
}
|
||||
|
@ -120,7 +121,7 @@ func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSON
|
|||
|
||||
// ContainerExecInspect returns low-level information about the exec
|
||||
// command. An error is returned if the exec cannot be found.
|
||||
func (daemon *Daemon) ContainerExecInspect(id string) (*ExecConfig, error) {
|
||||
func (daemon *Daemon) ContainerExecInspect(ctx context.Context, id string) (*ExecConfig, error) {
|
||||
eConfig, err := daemon.getExecConfig(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -130,7 +131,7 @@ func (daemon *Daemon) ContainerExecInspect(id string) (*ExecConfig, error) {
|
|||
|
||||
// VolumeInspect looks up a volume by name. An error is returned if
|
||||
// the volume cannot be found.
|
||||
func (daemon *Daemon) VolumeInspect(name string) (*types.Volume, error) {
|
||||
func (daemon *Daemon) VolumeInspect(ctx context.Context, name string) (*types.Volume, error) {
|
||||
v, err := daemon.volumes.Get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
package daemon
|
||||
|
||||
import "github.com/docker/docker/api/types"
|
||||
import (
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/context"
|
||||
)
|
||||
|
||||
// This sets platform-specific fields
|
||||
func setPlatformSpecificContainerFields(container *Container, contJSONBase *types.ContainerJSONBase) *types.ContainerJSONBase {
|
||||
|
@ -15,8 +18,8 @@ func setPlatformSpecificContainerFields(container *Container, contJSONBase *type
|
|||
}
|
||||
|
||||
// ContainerInspectPre120 gets containers for pre 1.20 APIs.
|
||||
func (daemon *Daemon) ContainerInspectPre120(name string) (*types.ContainerJSONPre120, error) {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerInspectPre120(ctx context.Context, name string) (*types.ContainerJSONPre120, error) {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -24,7 +27,7 @@ func (daemon *Daemon) ContainerInspectPre120(name string) (*types.ContainerJSONP
|
|||
container.Lock()
|
||||
defer container.Unlock()
|
||||
|
||||
base, err := daemon.getInspectData(container)
|
||||
base, err := daemon.getInspectData(ctx, container)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package daemon
|
||||
|
||||
import "github.com/docker/docker/api/types"
|
||||
import (
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/context"
|
||||
)
|
||||
|
||||
// This sets platform-specific fields
|
||||
func setPlatformSpecificContainerFields(container *Container, contJSONBase *types.ContainerJSONBase) *types.ContainerJSONBase {
|
||||
|
@ -12,6 +15,6 @@ func addMountPoints(container *Container) []types.MountPoint {
|
|||
}
|
||||
|
||||
// ContainerInspectPre120 get containers for pre 1.20 APIs.
|
||||
func (daemon *Daemon) ContainerInspectPre120(name string) (*types.ContainerJSON, error) {
|
||||
return daemon.ContainerInspect(name)
|
||||
func (daemon *Daemon) ContainerInspectPre120(ctx context.Context, name string) (*types.ContainerJSON, error) {
|
||||
return daemon.ContainerInspect(ctx, name)
|
||||
}
|
||||
|
|
|
@ -1,25 +1,29 @@
|
|||
package daemon
|
||||
|
||||
import "syscall"
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
)
|
||||
|
||||
// ContainerKill send signal to the container
|
||||
// If no signal is given (sig 0), then Kill with SIGKILL and wait
|
||||
// for the container to exit.
|
||||
// If a signal is given, then just send it to the container and return.
|
||||
func (daemon *Daemon) ContainerKill(name string, sig uint64) error {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerKill(ctx context.Context, name string, sig uint64) error {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If no signal is passed, or SIGKILL, perform regular Kill (SIGKILL + wait())
|
||||
if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL {
|
||||
if err := container.Kill(); err != nil {
|
||||
if err := container.Kill(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Otherwise, just send the requested signal
|
||||
if err := container.killSig(int(sig)); err != nil {
|
||||
if err := container.killSig(ctx, int(sig)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/context"
|
||||
derr "github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/graphdb"
|
||||
|
@ -20,7 +21,7 @@ type iterationAction int
|
|||
|
||||
// containerReducer represents a reducer for a container.
|
||||
// Returns the object to serialize by the api.
|
||||
type containerReducer func(*Container, *listContext) (*types.Container, error)
|
||||
type containerReducer func(context.Context, *Container, *listContext) (*types.Container, error)
|
||||
|
||||
const (
|
||||
// includeContainer is the action to include a container in the reducer.
|
||||
|
@ -35,7 +36,7 @@ const (
|
|||
var errStopIteration = errors.New("container list iteration stopped")
|
||||
|
||||
// List returns an array of all containers registered in the daemon.
|
||||
func (daemon *Daemon) List() []*Container {
|
||||
func (daemon *Daemon) List(ctx context.Context) []*Container {
|
||||
return daemon.containers.List()
|
||||
}
|
||||
|
||||
|
@ -79,21 +80,21 @@ type listContext struct {
|
|||
}
|
||||
|
||||
// Containers returns the list of containers to show given the user's filtering.
|
||||
func (daemon *Daemon) Containers(config *ContainersConfig) ([]*types.Container, error) {
|
||||
return daemon.reduceContainers(config, daemon.transformContainer)
|
||||
func (daemon *Daemon) Containers(ctx context.Context, config *ContainersConfig) ([]*types.Container, error) {
|
||||
return daemon.reduceContainers(ctx, config, daemon.transformContainer)
|
||||
}
|
||||
|
||||
// reduceContainer parses the user filtering and generates the list of containers to return based on a reducer.
|
||||
func (daemon *Daemon) reduceContainers(config *ContainersConfig, reducer containerReducer) ([]*types.Container, error) {
|
||||
func (daemon *Daemon) reduceContainers(ctx context.Context, config *ContainersConfig, reducer containerReducer) ([]*types.Container, error) {
|
||||
containers := []*types.Container{}
|
||||
|
||||
ctx, err := daemon.foldFilter(config)
|
||||
fctx, err := daemon.foldFilter(ctx, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, container := range daemon.List() {
|
||||
t, err := daemon.reducePsContainer(container, ctx, reducer)
|
||||
for _, container := range daemon.List(ctx) {
|
||||
t, err := daemon.reducePsContainer(ctx, container, fctx, reducer)
|
||||
if err != nil {
|
||||
if err != errStopIteration {
|
||||
return nil, err
|
||||
|
@ -102,19 +103,19 @@ func (daemon *Daemon) reduceContainers(config *ContainersConfig, reducer contain
|
|||
}
|
||||
if t != nil {
|
||||
containers = append(containers, t)
|
||||
ctx.idx++
|
||||
fctx.idx++
|
||||
}
|
||||
}
|
||||
return containers, nil
|
||||
}
|
||||
|
||||
// reducePsContainer is the basic representation for a container as expected by the ps command.
|
||||
func (daemon *Daemon) reducePsContainer(container *Container, ctx *listContext, reducer containerReducer) (*types.Container, error) {
|
||||
func (daemon *Daemon) reducePsContainer(ctx context.Context, container *Container, lctx *listContext, reducer containerReducer) (*types.Container, error) {
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
|
||||
// filter containers to return
|
||||
action := includeContainerInList(container, ctx)
|
||||
action := includeContainerInList(container, lctx)
|
||||
switch action {
|
||||
case excludeContainer:
|
||||
return nil, nil
|
||||
|
@ -123,11 +124,11 @@ func (daemon *Daemon) reducePsContainer(container *Container, ctx *listContext,
|
|||
}
|
||||
|
||||
// transform internal container struct into api structs
|
||||
return reducer(container, ctx)
|
||||
return reducer(ctx, container, lctx)
|
||||
}
|
||||
|
||||
// foldFilter generates the container filter based in the user's filtering options.
|
||||
func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error) {
|
||||
func (daemon *Daemon) foldFilter(ctx context.Context, config *ContainersConfig) (*listContext, error) {
|
||||
psFilters, err := filters.FromParam(config.Filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -159,11 +160,11 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error)
|
|||
var ancestorFilter bool
|
||||
if ancestors, ok := psFilters["ancestor"]; ok {
|
||||
ancestorFilter = true
|
||||
byParents := daemon.Graph().ByParent()
|
||||
byParents := daemon.Graph(ctx).ByParent()
|
||||
// The idea is to walk the graph down the most "efficient" way.
|
||||
for _, ancestor := range ancestors {
|
||||
// First, get the imageId of the ancestor filter (yay)
|
||||
image, err := daemon.Repositories().LookupImage(ancestor)
|
||||
image, err := daemon.Repositories(ctx).LookupImage(ancestor)
|
||||
if err != nil {
|
||||
logrus.Warnf("Error while looking up for image %v", ancestor)
|
||||
continue
|
||||
|
@ -185,14 +186,14 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error)
|
|||
|
||||
var beforeCont, sinceCont *Container
|
||||
if config.Before != "" {
|
||||
beforeCont, err = daemon.Get(config.Before)
|
||||
beforeCont, err = daemon.Get(ctx, config.Before)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if config.Since != "" {
|
||||
sinceCont, err = daemon.Get(config.Since)
|
||||
sinceCont, err = daemon.Get(ctx, config.Since)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -286,13 +287,13 @@ func includeContainerInList(container *Container, ctx *listContext) iterationAct
|
|||
}
|
||||
|
||||
// transformContainer generates the container type expected by the docker ps command.
|
||||
func (daemon *Daemon) transformContainer(container *Container, ctx *listContext) (*types.Container, error) {
|
||||
func (daemon *Daemon) transformContainer(ctx context.Context, container *Container, lctx *listContext) (*types.Container, error) {
|
||||
newC := &types.Container{
|
||||
ID: container.ID,
|
||||
Names: ctx.names[container.ID],
|
||||
Names: lctx.names[container.ID],
|
||||
}
|
||||
|
||||
img, err := daemon.Repositories().LookupImage(container.Config.Image)
|
||||
img, err := daemon.Repositories(ctx).LookupImage(container.Config.Image)
|
||||
if err != nil {
|
||||
// If the image can no longer be found by its original reference,
|
||||
// it makes sense to show the ID instead of a stale reference.
|
||||
|
@ -349,8 +350,8 @@ func (daemon *Daemon) transformContainer(container *Container, ctx *listContext)
|
|||
}
|
||||
}
|
||||
|
||||
if ctx.Size {
|
||||
sizeRw, sizeRootFs := container.getSize()
|
||||
if lctx.Size {
|
||||
sizeRw, sizeRootFs := container.getSize(ctx)
|
||||
newC.SizeRw = sizeRw
|
||||
newC.SizeRootFs = sizeRootFs
|
||||
}
|
||||
|
@ -361,7 +362,7 @@ func (daemon *Daemon) transformContainer(container *Container, ctx *listContext)
|
|||
|
||||
// Volumes lists known volumes, using the filter to restrict the range
|
||||
// of volumes returned.
|
||||
func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, error) {
|
||||
func (daemon *Daemon) Volumes(ctx context.Context, filter string) ([]*types.Volume, error) {
|
||||
var volumesOut []*types.Volume
|
||||
volFilters, err := filters.FromParam(filter)
|
||||
if err != nil {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/logger"
|
||||
derr "github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
|
@ -30,7 +31,7 @@ type ContainerLogsConfig struct {
|
|||
|
||||
// ContainerLogs hooks up a container's stdout and stderr streams
|
||||
// configured with the given struct.
|
||||
func (daemon *Daemon) ContainerLogs(container *Container, config *ContainerLogsConfig) error {
|
||||
func (daemon *Daemon) ContainerLogs(ctx context.Context, container *Container, config *ContainerLogsConfig) error {
|
||||
if !(config.UseStdout || config.UseStderr) {
|
||||
return derr.ErrorCodeNeedStream
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/runconfig"
|
||||
|
@ -84,9 +85,9 @@ func (m *containerMonitor) ExitOnNext() {
|
|||
|
||||
// Close closes the container's resources such as networking allocations and
|
||||
// unmounts the contatiner's root filesystem
|
||||
func (m *containerMonitor) Close() error {
|
||||
func (m *containerMonitor) Close(ctx context.Context) error {
|
||||
// Cleanup networking and mounts
|
||||
m.container.cleanup()
|
||||
m.container.cleanup(ctx)
|
||||
|
||||
// FIXME: here is race condition between two RUN instructions in Dockerfile
|
||||
// because they share same runconfig and change image. Must be fixed
|
||||
|
@ -101,7 +102,7 @@ func (m *containerMonitor) Close() error {
|
|||
}
|
||||
|
||||
// Start starts the containers process and monitors it according to the restart policy
|
||||
func (m *containerMonitor) Start() error {
|
||||
func (m *containerMonitor) Start(ctx context.Context) error {
|
||||
var (
|
||||
err error
|
||||
exitStatus execdriver.ExitStatus
|
||||
|
@ -117,7 +118,7 @@ func (m *containerMonitor) Start() error {
|
|||
m.container.setStopped(&exitStatus)
|
||||
defer m.container.Unlock()
|
||||
}
|
||||
m.Close()
|
||||
m.Close(ctx)
|
||||
}()
|
||||
// reset stopped flag
|
||||
if m.container.HasBeenManuallyStopped {
|
||||
|
@ -138,11 +139,11 @@ func (m *containerMonitor) Start() error {
|
|||
|
||||
pipes := execdriver.NewPipes(m.container.stdin, m.container.stdout, m.container.stderr, m.container.Config.OpenStdin)
|
||||
|
||||
m.container.logEvent("start")
|
||||
m.container.logEvent(ctx, "start")
|
||||
|
||||
m.lastStartTime = time.Now()
|
||||
|
||||
if exitStatus, err = m.container.daemon.run(m.container, pipes, m.callback); err != nil {
|
||||
if exitStatus, err = m.container.daemon.run(ctx, m.container, pipes, m.callback); err != nil {
|
||||
// if we receive an internal error from the initial start of a container then lets
|
||||
// return it instead of entering the restart loop
|
||||
if m.container.RestartCount == 0 {
|
||||
|
@ -162,7 +163,7 @@ func (m *containerMonitor) Start() error {
|
|||
|
||||
if m.shouldRestart(exitStatus.ExitCode) {
|
||||
m.container.setRestarting(&exitStatus)
|
||||
m.container.logEvent("die")
|
||||
m.container.logEvent(ctx, "die")
|
||||
m.resetContainer(true)
|
||||
|
||||
// sleep with a small time increment between each restart to help avoid issues cased by quickly
|
||||
|
@ -177,7 +178,7 @@ func (m *containerMonitor) Start() error {
|
|||
continue
|
||||
}
|
||||
|
||||
m.container.logEvent("die")
|
||||
m.container.logEvent(ctx, "die")
|
||||
m.resetContainer(true)
|
||||
return err
|
||||
}
|
||||
|
@ -245,11 +246,11 @@ func (m *containerMonitor) shouldRestart(exitCode int) bool {
|
|||
|
||||
// callback ensures that the container's state is properly updated after we
|
||||
// received ack from the execution drivers
|
||||
func (m *containerMonitor) callback(processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error {
|
||||
func (m *containerMonitor) callback(ctx context.Context, processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error {
|
||||
go func() {
|
||||
_, ok := <-chOOM
|
||||
if ok {
|
||||
m.container.logEvent("oom")
|
||||
m.container.logEvent(ctx, "oom")
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/context"
|
||||
derr "github.com/docker/docker/errors"
|
||||
)
|
||||
|
||||
// ContainerPause pauses a container
|
||||
func (daemon *Daemon) ContainerPause(name string) error {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerPause(ctx context.Context, name string) error {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := container.pause(); err != nil {
|
||||
if err := container.pause(ctx); err != nil {
|
||||
return derr.ErrorCodePauseError.WithArgs(name, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/context"
|
||||
derr "github.com/docker/docker/errors"
|
||||
)
|
||||
|
||||
// ContainerRename changes the name of a container, using the oldName
|
||||
// to find the container. An error is returned if newName is already
|
||||
// reserved.
|
||||
func (daemon *Daemon) ContainerRename(oldName, newName string) error {
|
||||
func (daemon *Daemon) ContainerRename(ctx context.Context, oldName, newName string) error {
|
||||
if oldName == "" || newName == "" {
|
||||
return derr.ErrorCodeEmptyRename
|
||||
}
|
||||
|
||||
container, err := daemon.Get(oldName)
|
||||
container, err := daemon.Get(ctx, oldName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -21,7 +22,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
|
|||
|
||||
container.Lock()
|
||||
defer container.Unlock()
|
||||
if newName, err = daemon.reserveName(container.ID, newName); err != nil {
|
||||
if newName, err = daemon.reserveName(ctx, container.ID, newName); err != nil {
|
||||
return derr.ErrorCodeRenameTaken.WithArgs(err)
|
||||
}
|
||||
|
||||
|
@ -29,7 +30,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
|
|||
|
||||
undo := func() {
|
||||
container.Name = oldName
|
||||
daemon.reserveName(container.ID, oldName)
|
||||
daemon.reserveName(ctx, container.ID, oldName)
|
||||
daemon.containerGraphDB.Delete(newName)
|
||||
}
|
||||
|
||||
|
@ -43,6 +44,6 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
container.logEvent("rename")
|
||||
container.logEvent(ctx, "rename")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/context"
|
||||
)
|
||||
|
||||
// ContainerResize changes the size of the TTY of the process running
|
||||
// in the container with the given name to the given height and width.
|
||||
func (daemon *Daemon) ContainerResize(name string, height, width int) error {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerResize(ctx context.Context, name string, height, width int) error {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return container.Resize(height, width)
|
||||
return container.Resize(ctx, height, width)
|
||||
}
|
||||
|
||||
// ContainerExecResize changes the size of the TTY of the process
|
||||
// running in the exec with the given name to the given height and
|
||||
// width.
|
||||
func (daemon *Daemon) ContainerExecResize(name string, height, width int) error {
|
||||
func (daemon *Daemon) ContainerExecResize(ctx context.Context, name string, height, width int) error {
|
||||
ExecConfig, err := daemon.getExecConfig(name)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/context"
|
||||
derr "github.com/docker/docker/errors"
|
||||
)
|
||||
|
||||
|
@ -10,12 +11,12 @@ import (
|
|||
// timeout, ContainerRestart will wait forever until a graceful
|
||||
// stop. Returns an error if the container cannot be found, or if
|
||||
// there is an underlying error at any stage of the restart.
|
||||
func (daemon *Daemon) ContainerRestart(name string, seconds int) error {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerRestart(ctx context.Context, name string, seconds int) error {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Restart(seconds); err != nil {
|
||||
if err := container.Restart(ctx, seconds); err != nil {
|
||||
return derr.ErrorCodeCantRestart.WithArgs(name, err)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -3,14 +3,15 @@ package daemon
|
|||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
derr "github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/docker/utils"
|
||||
)
|
||||
|
||||
// ContainerStart starts a container.
|
||||
func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConfig) error {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerStart(ctx context.Context, name string, hostConfig *runconfig.HostConfig) error {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -28,7 +29,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConf
|
|||
// This is kept for backward compatibility - hostconfig should be passed when
|
||||
// creating a container, not during start.
|
||||
if hostConfig != nil {
|
||||
if err := daemon.setHostConfig(container, hostConfig); err != nil {
|
||||
if err := daemon.setHostConfig(ctx, container, hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -40,11 +41,11 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConf
|
|||
|
||||
// check if hostConfig is in line with the current system settings.
|
||||
// It may happen cgroups are umounted or the like.
|
||||
if _, err = daemon.verifyContainerSettings(container.hostConfig, nil); err != nil {
|
||||
if _, err = daemon.verifyContainerSettings(ctx, container.hostConfig, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := container.Start(); err != nil {
|
||||
if err := container.Start(ctx); err != nil {
|
||||
return derr.ErrorCodeCantStart.WithArgs(name, utils.GetErrorMessage(err))
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/pkg/version"
|
||||
"github.com/docker/libnetwork/osl"
|
||||
|
@ -22,9 +23,9 @@ type ContainerStatsConfig struct {
|
|||
|
||||
// ContainerStats writes information about the container to the stream
|
||||
// given in the config object.
|
||||
func (daemon *Daemon) ContainerStats(prefixOrName string, config *ContainerStatsConfig) error {
|
||||
func (daemon *Daemon) ContainerStats(ctx context.Context, prefixOrName string, config *ContainerStatsConfig) error {
|
||||
|
||||
container, err := daemon.Get(prefixOrName)
|
||||
container, err := daemon.Get(ctx, prefixOrName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/context"
|
||||
derr "github.com/docker/docker/errors"
|
||||
)
|
||||
|
||||
|
@ -10,15 +11,15 @@ import (
|
|||
// will wait for a graceful termination. An error is returned if the
|
||||
// container is not found, is already stopped, or if there is a
|
||||
// problem stopping the container.
|
||||
func (daemon *Daemon) ContainerStop(name string, seconds int) error {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerStop(ctx context.Context, name string, seconds int) error {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !container.IsRunning() {
|
||||
return derr.ErrorCodeStopped
|
||||
}
|
||||
if err := container.Stop(seconds); err != nil {
|
||||
if err := container.Stop(ctx, seconds); err != nil {
|
||||
return derr.ErrorCodeCantStop.WithArgs(name, err)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/context"
|
||||
derr "github.com/docker/docker/errors"
|
||||
)
|
||||
|
||||
|
@ -16,12 +17,12 @@ import (
|
|||
// "-ef" if no args are given. An error is returned if the container
|
||||
// is not found, or is not running, or if there are any problems
|
||||
// running ps, or parsing the output.
|
||||
func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error) {
|
||||
func (daemon *Daemon) ContainerTop(ctx context.Context, name string, psArgs string) (*types.ContainerProcessList, error) {
|
||||
if psArgs == "" {
|
||||
psArgs = "-ef"
|
||||
}
|
||||
|
||||
container, err := daemon.Get(name)
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -30,7 +31,7 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.Container
|
|||
return nil, derr.ErrorCodeNotRunning.WithArgs(name)
|
||||
}
|
||||
|
||||
pids, err := daemon.ExecutionDriver().GetPidsForContainer(container.ID)
|
||||
pids, err := daemon.ExecutionDriver(ctx).GetPidsForContainer(container.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -76,6 +77,6 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.Container
|
|||
}
|
||||
}
|
||||
}
|
||||
container.logEvent("top")
|
||||
container.logEvent(ctx, "top")
|
||||
return procList, nil
|
||||
}
|
||||
|
|
|
@ -2,10 +2,11 @@ package daemon
|
|||
|
||||
import (
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/context"
|
||||
derr "github.com/docker/docker/errors"
|
||||
)
|
||||
|
||||
// ContainerTop is not supported on Windows and returns an error.
|
||||
func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error) {
|
||||
func (daemon *Daemon) ContainerTop(ctx context.Context, name string, psArgs string) (*types.ContainerProcessList, error) {
|
||||
return nil, derr.ErrorCodeNoTop
|
||||
}
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/context"
|
||||
derr "github.com/docker/docker/errors"
|
||||
)
|
||||
|
||||
// ContainerUnpause unpauses a container
|
||||
func (daemon *Daemon) ContainerUnpause(name string) error {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerUnpause(ctx context.Context, name string) error {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := container.unpause(); err != nil {
|
||||
if err := container.unpause(ctx); err != nil {
|
||||
return derr.ErrorCodeCantUnpause.WithArgs(name, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
derr "github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
|
@ -285,7 +286,7 @@ func parseVolumesFrom(spec string) (string, string, error) {
|
|||
// 1. Select the previously configured mount points for the containers, if any.
|
||||
// 2. Select the volumes mounted from another containers. Overrides previously configured mount point destination.
|
||||
// 3. Select the bind mounts set by the client. Overrides previously configured mount point destinations.
|
||||
func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error {
|
||||
func (daemon *Daemon) registerMountPoints(ctx context.Context, container *Container, hostConfig *runconfig.HostConfig) error {
|
||||
binds := map[string]bool{}
|
||||
mountPoints := map[string]*mountPoint{}
|
||||
|
||||
|
@ -301,7 +302,7 @@ func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runc
|
|||
return err
|
||||
}
|
||||
|
||||
c, err := daemon.Get(containerID)
|
||||
c, err := daemon.Get(ctx, containerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/runconfig"
|
||||
)
|
||||
|
@ -31,6 +32,6 @@ func (daemon *Daemon) verifyVolumesInfo(container *Container) error {
|
|||
// registerMountPoints initializes the container mount points with the
|
||||
// configured volumes and bind mounts. Windows does not support volumes or
|
||||
// mount points.
|
||||
func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error {
|
||||
func (daemon *Daemon) registerMountPoints(ctx context.Context, container *Container, hostConfig *runconfig.HostConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
package daemon
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
)
|
||||
|
||||
// ContainerWait stops processing until the given container is
|
||||
// stopped. If the container is not found, an error is returned. On a
|
||||
// successful stop, the exit code of the container is returned. On a
|
||||
// timeout, an error is returned. If you want to wait forever, supply
|
||||
// a negative duration for the timeout.
|
||||
func (daemon *Daemon) ContainerWait(name string, timeout time.Duration) (int, error) {
|
||||
container, err := daemon.Get(name)
|
||||
func (daemon *Daemon) ContainerWait(ctx context.Context, name string, timeout time.Duration) (int, error) {
|
||||
container, err := daemon.Get(ctx, name)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/docker/docker/autogen/dockerversion"
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/daemon"
|
||||
"github.com/docker/docker/daemon/logger"
|
||||
"github.com/docker/docker/opts"
|
||||
|
@ -150,6 +151,11 @@ func getGlobalFlag() (globalFlag *flag.Flag) {
|
|||
|
||||
// CmdDaemon is the daemon command, called the raw arguments after `docker daemon`.
|
||||
func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
||||
// This may need to be made even more global - it all depends
|
||||
// on whether we want the CLI to have a context object too.
|
||||
// For now we'll leave it as a daemon-side object only.
|
||||
ctx := context.Background()
|
||||
|
||||
// warn from uuid package when running the daemon
|
||||
uuid.Loggerf = logrus.Warnf
|
||||
|
||||
|
@ -224,7 +230,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
|||
serverConfig.TLSConfig = tlsConfig
|
||||
}
|
||||
|
||||
api := apiserver.New(serverConfig)
|
||||
api := apiserver.New(ctx, serverConfig)
|
||||
|
||||
// The serve API routine never exits unless an error occurs
|
||||
// We need to start it as a goroutine and wait on it so
|
||||
|
@ -245,7 +251,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
|||
cli.TrustKeyPath = commonFlags.TrustKey
|
||||
|
||||
registryService := registry.NewService(cli.registryOptions)
|
||||
d, err := daemon.NewDaemon(cli.Config, registryService)
|
||||
d, err := daemon.NewDaemon(ctx, cli.Config, registryService)
|
||||
if err != nil {
|
||||
if pfile != nil {
|
||||
if err := pfile.Remove(); err != nil {
|
||||
|
@ -260,14 +266,14 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
|||
logrus.WithFields(logrus.Fields{
|
||||
"version": dockerversion.VERSION,
|
||||
"commit": dockerversion.GITCOMMIT,
|
||||
"execdriver": d.ExecutionDriver().Name(),
|
||||
"graphdriver": d.GraphDriver().String(),
|
||||
"execdriver": d.ExecutionDriver(ctx).Name(),
|
||||
"graphdriver": d.GraphDriver(ctx).String(),
|
||||
}).Info("Docker daemon")
|
||||
|
||||
signal.Trap(func() {
|
||||
api.Close()
|
||||
<-serveAPIWait
|
||||
shutdownDaemon(d, 15)
|
||||
shutdownDaemon(ctx, d, 15)
|
||||
if pfile != nil {
|
||||
if err := pfile.Remove(); err != nil {
|
||||
logrus.Error(err)
|
||||
|
@ -277,12 +283,12 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
|||
|
||||
// after the daemon is done setting up we can tell the api to start
|
||||
// accepting connections with specified daemon
|
||||
api.AcceptConnections(d)
|
||||
api.AcceptConnections(ctx, d)
|
||||
|
||||
// Daemon is fully initialized and handling API traffic
|
||||
// Wait for serve API to complete
|
||||
errAPI := <-serveAPIWait
|
||||
shutdownDaemon(d, 15)
|
||||
shutdownDaemon(ctx, d, 15)
|
||||
if errAPI != nil {
|
||||
if pfile != nil {
|
||||
if err := pfile.Remove(); err != nil {
|
||||
|
@ -297,10 +303,10 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
|||
// shutdownDaemon just wraps daemon.Shutdown() to handle a timeout in case
|
||||
// d.Shutdown() is waiting too long to kill container or worst it's
|
||||
// blocked there
|
||||
func shutdownDaemon(d *daemon.Daemon, timeout time.Duration) {
|
||||
func shutdownDaemon(ctx context.Context, d *daemon.Daemon, timeout time.Duration) {
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
d.Shutdown()
|
||||
d.Shutdown(ctx)
|
||||
close(ch)
|
||||
}()
|
||||
select {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/pkg/httputils"
|
||||
"github.com/docker/docker/pkg/progressreader"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
|
@ -16,7 +17,7 @@ import (
|
|||
// inConfig (if src is "-"), or from a URI specified in src. Progress output is
|
||||
// written to outStream. Repository and tag names can optionally be given in
|
||||
// the repo and tag arguments, respectively.
|
||||
func (s *TagStore) Import(src string, repo string, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, containerConfig *runconfig.Config) error {
|
||||
func (s *TagStore) Import(ctx context.Context, src string, repo string, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, containerConfig *runconfig.Config) error {
|
||||
var (
|
||||
sf = streamformatter.NewJSONStreamFormatter()
|
||||
archive io.ReadCloser
|
||||
|
@ -74,6 +75,6 @@ func (s *TagStore) Import(src string, repo string, tag string, msg string, inCon
|
|||
logID = utils.ImageReference(logID, tag)
|
||||
}
|
||||
|
||||
s.eventsService.Log("import", logID, "")
|
||||
s.eventsService.Log(ctx, "import", logID, "")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/utils"
|
||||
|
@ -62,7 +63,7 @@ func NewPuller(s *TagStore, endpoint registry.APIEndpoint, repoInfo *registry.Re
|
|||
|
||||
// Pull initiates a pull operation. image is the repository name to pull, and
|
||||
// tag may be either empty, or indicate a specific tag to pull.
|
||||
func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConfig) error {
|
||||
func (s *TagStore) Pull(ctx context.Context, image string, tag string, imagePullConfig *ImagePullConfig) error {
|
||||
var sf = streamformatter.NewJSONStreamFormatter()
|
||||
|
||||
// Resolve the Repository name from fqn to RepositoryInfo
|
||||
|
@ -131,7 +132,7 @@ func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConf
|
|||
|
||||
}
|
||||
|
||||
s.eventsService.Log("pull", logName, "")
|
||||
s.eventsService.Log(ctx, "pull", logName, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/context"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/docker/registry"
|
||||
)
|
||||
|
@ -67,7 +68,7 @@ func (s *TagStore) NewPusher(endpoint registry.APIEndpoint, localRepo Repository
|
|||
}
|
||||
|
||||
// Push initiates a push operation on the repository named localName.
|
||||
func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) error {
|
||||
func (s *TagStore) Push(ctx context.Context, localName string, imagePushConfig *ImagePushConfig) error {
|
||||
// FIXME: Allow to interrupt current push when new push of same image is done.
|
||||
|
||||
var sf = streamformatter.NewJSONStreamFormatter()
|
||||
|
@ -115,7 +116,7 @@ func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) erro
|
|||
|
||||
}
|
||||
|
||||
s.eventsService.Log("push", repoInfo.LocalName, "")
|
||||
s.eventsService.Log(ctx, "push", repoInfo.LocalName, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -410,7 +410,7 @@ func (s *DockerSuite) TestEventsFilterContainer(c *check.C) {
|
|||
}
|
||||
|
||||
// Check the id
|
||||
parsedID := strings.TrimSuffix(e[1], ":")
|
||||
parsedID := strings.TrimSuffix(e[3], ":")
|
||||
if parsedID != id {
|
||||
return fmt.Errorf("expected event for container id %s: %s - parsed container id: %s", id, event, parsedID)
|
||||
}
|
||||
|
@ -686,3 +686,78 @@ func (s *DockerRegistrySuite) TestEventsImageFilterPush(c *check.C) {
|
|||
c.Fatalf("Missing 'push' log event for image %s\n%s", repoName, out)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestEventsReqID(c *check.C) {
|
||||
// Tests for the "[reqid: xxx]" field in Events
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
reqIDMatch := `[^ ]+ \[reqid: ([0-9a-z]{12})\] [0-9a-z]+: `
|
||||
reqIDRE := regexp.MustCompile(reqIDMatch)
|
||||
|
||||
// Simple test just to make sure it works at all
|
||||
dockerCmd(c, "create", "busybox", "true")
|
||||
|
||||
out, _ := dockerCmd(c, "events", "--since=0", "--until=0s")
|
||||
events := strings.Split(strings.TrimSpace(out), "\n")
|
||||
|
||||
if len(events) == 0 {
|
||||
c.Fatalf("Wrong # of events, should just be one, got:\n%v\n", events)
|
||||
}
|
||||
|
||||
createEvent := events[len(events)-1]
|
||||
|
||||
matched, err := regexp.MatchString(reqIDMatch, createEvent)
|
||||
if err != nil || !matched {
|
||||
c.Fatalf("Error finding reqID in event: %v\n", createEvent)
|
||||
}
|
||||
|
||||
reqID1 := reqIDRE.FindStringSubmatch(createEvent)[1]
|
||||
|
||||
// Now make sure another cmd doesn't get the same reqID
|
||||
dockerCmd(c, "create", "busybox", "true")
|
||||
|
||||
out, _ = dockerCmd(c, "events", "--since=0", "--until=0s")
|
||||
events = strings.Split(strings.TrimSpace(out), "\n")
|
||||
createEvent = events[len(events)-1]
|
||||
|
||||
matched, err = regexp.MatchString(reqIDMatch, createEvent)
|
||||
if err != nil || !matched {
|
||||
c.Fatalf("Error finding reqID in event: %v\n", createEvent)
|
||||
}
|
||||
|
||||
reqID2 := reqIDRE.FindStringSubmatch(createEvent)[1]
|
||||
|
||||
if reqID1 == reqID2 {
|
||||
c.Fatalf("Should not have the same reqID(%s):\n%v\n", reqID1, createEvent)
|
||||
}
|
||||
|
||||
// Now make sure a build **does** use the same reqID for all
|
||||
// 4 events that are generated
|
||||
_, err = buildImage("reqidimg", `
|
||||
FROM busybox
|
||||
RUN echo HI`, true)
|
||||
if err != nil {
|
||||
c.Fatalf("Couldn't create image: %q", err)
|
||||
}
|
||||
|
||||
out, _ = dockerCmd(c, "events", "--since=0", "--until=0s")
|
||||
events = strings.Split(strings.TrimSpace(out), "\n")
|
||||
|
||||
// Get last event's reqID - will use it to find other matching events
|
||||
lastEvent := events[len(events)-1]
|
||||
reqID := reqIDRE.FindStringSubmatch(lastEvent)[1]
|
||||
|
||||
// Find all events with this same reqID
|
||||
eventList := []string{lastEvent}
|
||||
for i := len(events) - 2; i >= 0; i-- {
|
||||
tmpID := reqIDRE.FindStringSubmatch(events[i])[1]
|
||||
if tmpID != reqID {
|
||||
break
|
||||
}
|
||||
eventList = append(eventList, events[i])
|
||||
}
|
||||
|
||||
if len(eventList) != 5 { // create, start, die, commit, destroy
|
||||
c.Fatalf("Wrong # of matching events - should be 5:\n%q\n", eventList)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ func (p *JSONProgress) String() string {
|
|||
// the created time, where it from, status, ID of the
|
||||
// message. It's used for docker events.
|
||||
type JSONMessage struct {
|
||||
RequestID string `json:"reqid,omitempty"`
|
||||
Stream string `json:"stream,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Progress *JSONProgress `json:"progressDetail,omitempty"`
|
||||
|
@ -127,6 +128,9 @@ func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error {
|
|||
} else if jm.Time != 0 {
|
||||
fmt.Fprintf(out, "%s ", time.Unix(jm.Time, 0).Format(timeutils.RFC3339NanoFixed))
|
||||
}
|
||||
if jm.RequestID != "" {
|
||||
fmt.Fprintf(out, "[reqid: %s] ", jm.RequestID)
|
||||
}
|
||||
if jm.ID != "" {
|
||||
fmt.Fprintf(out, "%s: ", jm.ID)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue