github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/api/handlers/compat/containers_attach.go (about) 1 package compat 2 3 import ( 4 "net/http" 5 6 "github.com/containers/podman/v2/libpod" 7 "github.com/containers/podman/v2/libpod/define" 8 "github.com/containers/podman/v2/pkg/api/handlers/utils" 9 "github.com/containers/podman/v2/pkg/api/server/idle" 10 "github.com/gorilla/schema" 11 "github.com/pkg/errors" 12 "github.com/sirupsen/logrus" 13 ) 14 15 func AttachContainer(w http.ResponseWriter, r *http.Request) { 16 runtime := r.Context().Value("runtime").(*libpod.Runtime) 17 decoder := r.Context().Value("decoder").(*schema.Decoder) 18 19 query := struct { 20 DetachKeys string `schema:"detachKeys"` 21 Logs bool `schema:"logs"` 22 Stream bool `schema:"stream"` 23 Stdin bool `schema:"stdin"` 24 Stdout bool `schema:"stdout"` 25 Stderr bool `schema:"stderr"` 26 }{ 27 Stream: true, 28 } 29 if err := decoder.Decode(&query, r.URL.Query()); err != nil { 30 utils.Error(w, "Error parsing parameters", http.StatusBadRequest, err) 31 return 32 } 33 34 // Detach keys: explicitly set to "" is very different from unset 35 // TODO: Our format for parsing these may be different from Docker. 36 var detachKeys *string 37 if _, found := r.URL.Query()["detachKeys"]; found { 38 detachKeys = &query.DetachKeys 39 } 40 41 streams := new(libpod.HTTPAttachStreams) 42 streams.Stdout = true 43 streams.Stderr = true 44 streams.Stdin = true 45 useStreams := false 46 if _, found := r.URL.Query()["stdin"]; found { 47 streams.Stdin = query.Stdin 48 useStreams = true 49 } 50 if _, found := r.URL.Query()["stdout"]; found { 51 streams.Stdout = query.Stdout 52 useStreams = true 53 } 54 if _, found := r.URL.Query()["stderr"]; found { 55 streams.Stderr = query.Stderr 56 useStreams = true 57 } 58 if !useStreams { 59 streams = nil 60 } 61 if useStreams && !streams.Stdout && !streams.Stderr && !streams.Stdin { 62 utils.Error(w, "Parameter conflict", http.StatusBadRequest, errors.Errorf("at least one of stdin, stdout, stderr must be true")) 63 return 64 } 65 66 // At least one of these must be set 67 if !query.Stream && !query.Logs { 68 utils.Error(w, "Unsupported parameter", http.StatusBadRequest, errors.Errorf("at least one of Logs or Stream must be set")) 69 return 70 } 71 72 name := utils.GetName(r) 73 ctr, err := runtime.LookupContainer(name) 74 if err != nil { 75 utils.ContainerNotFound(w, name, err) 76 return 77 } 78 79 state, err := ctr.State() 80 if err != nil { 81 utils.InternalServerError(w, err) 82 return 83 } 84 // For Docker compatibility, we need to re-initialize containers in these states. 85 if state == define.ContainerStateConfigured || state == define.ContainerStateExited { 86 if err := ctr.Init(r.Context(), ctr.PodID() != ""); err != nil { 87 utils.Error(w, "Container in wrong state", http.StatusConflict, errors.Wrapf(err, "error preparing container %s for attach", ctr.ID())) 88 return 89 } 90 } else if !(state == define.ContainerStateCreated || state == define.ContainerStateRunning) { 91 utils.InternalServerError(w, errors.Wrapf(define.ErrCtrStateInvalid, "can only attach to created or running containers - currently in state %s", state.String())) 92 return 93 } 94 95 logErr := func(e error) { 96 logrus.Error(errors.Wrapf(e, "error attaching to container %s", ctr.ID())) 97 } 98 99 // Perform HTTP attach. 100 // HTTPAttach will handle everything about the connection from here on 101 // (including closing it and writing errors to it). 102 hijackChan := make(chan bool, 1) 103 err = ctr.HTTPAttach(r, w, streams, detachKeys, nil, query.Stream, query.Logs, hijackChan) 104 105 if <-hijackChan { 106 // If connection was Hijacked, we have to signal it's being closed 107 t := r.Context().Value("idletracker").(*idle.Tracker) 108 defer t.Close() 109 110 if err != nil { 111 // Cannot report error to client as a 500 as the Upgrade set status to 101 112 logErr(err) 113 } 114 } else { 115 // If the Hijack failed we are going to assume we can still inform client of failure 116 utils.InternalServerError(w, err) 117 logErr(err) 118 } 119 logrus.Debugf("Attach for container %s completed successfully", ctr.ID()) 120 }