diff options
-rw-r--r-- | pkg/api/handlers/compat/containers_stats.go | 30 | ||||
-rw-r--r-- | pkg/api/server/register_containers.go | 5 | ||||
-rw-r--r-- | test/apiv2/python/rest_api/test_v2_0_0_container.py | 4 |
3 files changed, 26 insertions, 13 deletions
diff --git a/pkg/api/handlers/compat/containers_stats.go b/pkg/api/handlers/compat/containers_stats.go index 694b57bb1..851955207 100644 --- a/pkg/api/handlers/compat/containers_stats.go +++ b/pkg/api/handlers/compat/containers_stats.go @@ -22,7 +22,8 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) { decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { - Stream bool `schema:"stream"` + Stream bool `schema:"stream"` + OneShot bool `schema:"one-shot"` //added schema for one shot }{ Stream: true, } @@ -30,6 +31,10 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) { utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) return } + if query.Stream && query.OneShot { // mismatch. one-shot can only be passed with stream=false + utils.Error(w, "invalid combination of stream and one-shot", http.StatusBadRequest, define.ErrInvalidArg) + return + } name := utils.GetName(r) ctnr, err := runtime.LookupContainer(name) @@ -56,6 +61,16 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) { return } + coder := json.NewEncoder(w) + // Write header and content type. + w.WriteHeader(http.StatusOK) + w.Header().Add("Content-Type", "application/json") + if flusher, ok := w.(http.Flusher); ok { + flusher.Flush() + } + + // Setup JSON encoder for streaming. + coder.SetEscapeHTML(true) var preRead time.Time var preCPUStats CPUStats if query.Stream { @@ -75,17 +90,6 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) { } } - // Write header and content type. - w.WriteHeader(http.StatusOK) - w.Header().Add("Content-Type", "application/json") - if flusher, ok := w.(http.Flusher); ok { - flusher.Flush() - } - - // Setup JSON encoder for streaming. - coder := json.NewEncoder(w) - coder.SetEscapeHTML(true) - streamLabel: // A label to flatten the scope select { case <-r.Context().Done(): @@ -199,7 +203,7 @@ streamLabel: // A label to flatten the scope flusher.Flush() } - if !query.Stream { + if !query.Stream || query.OneShot { return } diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go index 536c4707a..aa999905e 100644 --- a/pkg/api/server/register_containers.go +++ b/pkg/api/server/register_containers.go @@ -375,6 +375,11 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // type: boolean // default: true // description: Stream the output + // - in: query + // name: one-shot + // type: boolean + // default: false + // description: Provide a one-shot response in which preCPU stats are blank, resulting in a single cycle return. // produces: // - application/json // responses: diff --git a/test/apiv2/python/rest_api/test_v2_0_0_container.py b/test/apiv2/python/rest_api/test_v2_0_0_container.py index ad096ed38..f67013117 100644 --- a/test/apiv2/python/rest_api/test_v2_0_0_container.py +++ b/test/apiv2/python/rest_api/test_v2_0_0_container.py @@ -30,6 +30,10 @@ class ContainerTestCase(APITestCase): self.assertIn(r.status_code, (200, 409), r.text) if r.status_code == 200: self.assertId(r.content) + r = requests.get(self.uri(self.resolve_container("/containers/{}/stats?stream=false&one-shot=true"))) + self.assertIn(r.status_code, (200, 409), r.text) + if r.status_code == 200: + self.assertId(r.content) def test_delete(self): r = requests.delete(self.uri(self.resolve_container("/containers/{}"))) |